SRE-Agent-Signature header: an HMAC-SHA256 made with a key that belongs to your organization alone. Your proxy or application can check it to know that a request came from your organization’s configuration, not just from the platform’s shared address.
This page says what the header is, which requests carry it, where to find your key, how to verify at each hop, how to rotate the key and how to test a verifier before any traffic arrives. The key is on the Request Signing tab of Settings, which organization admins can open.
Why verify
The hosted platform reads your endpoints from one fixed address, 52.7.196.239, shared by every organization. The address proves nothing about which organization a request is for, so it must never be the only control on an endpoint. Keep requiring the credentials the endpoint already requires. The signature says that a request is for your organization. It never replaces your credentials. A request sent through a forwarder is made by the forwarder from your network, so it arrives from the forwarder’s address and not the platform’s. It carries the same header.What the header is
Fields are
name=value pairs separated by , with no spaces. The header never carries the key. The key is the string srsk_ followed by 43 characters. Use that whole string, as is, as the HMAC key: the bytes of its UTF-8 text, with no decoding step.
Every header whose name starts with sre-agent- is reserved for the platform. The platform removes any such header you configured on a data source or a synthetic check before it signs, and the forms refuse those names, so a copy of a signature can never travel from one organization’s configuration to another’s.
Which requests carry it
The platform signs a request to an endpoint named by your configuration when it is not signed with AWS credentials, the host is not an AWS service API endpoint and the host is not one of the third-party services listed below. That covers:- data source reads (Prometheus, Loki, Grafana, Tempo, Elasticsearch, Jaeger, Zipkin, and Datadog or New Relic when the URL is your own proxy) and the completion reads of the Explorer;
- synthetic HTTP checks from the central location, on every hop to the target’s own host (a hop to another host after a redirect is not signed);
- outbound alerting webhooks and Grafana annotations, signed afresh on every retry;
- Kubernetes API calls and the connector’s
http_health_check; - self-hosted AI endpoints (an Ollama, an OpenAI-compatible gateway or a Portkey of your own);
- self-hosted Jira (Data Center behind your own edge).
Your endpoints under AWS domains
These endpoints are yours even though they live under an AWS or AWS-related domain, so they are signed. Each pattern needs a label in front of it, on a label boundary.- An Application Load Balancer or Classic Load Balancer,
*.<region>.elb.amazonaws.com, and a Network Load Balancer,*.elb.<region>.amazonaws.com. - An API Gateway stage,
*.execute-api.<region>.amazonaws.com(and.vpce.amazonaws.com). - An S3 website endpoint,
*.s3-website*.amazonaws.com. - An EC2 public name,
ec2-<address>.compute-1.amazonaws.comandec2-<address>.<region>.compute.amazonaws.com. - CloudFront (
*.cloudfront.net), a Lambda function URL (*.lambda-url.<region>.on.aws), App Runner (*.awsapprunner.com) and Amplify (*.amplifyapp.com), which are not AWS service API hosts.
.amazonaws.com.cn) follows the same patterns.
What is never signed
- Requests that SRE Agent signs with AWS credentials, and requests to AWS service API hosts, for example
monitoring.<region>.amazonaws.com,aps-workspaces.<region>.amazonaws.comand an EKS API server. - TCP and DNS checks, which have no HTTP header to carry it.
- Requests to third-party services, matched by host or DNS suffix on a label boundary:
datadoghq.com,datadoghq.eu,ddog-gov.com,newrelic.com,grafana.net,elastic-cloud.com,cloud.es.io,found.io,atlassian.net,jira.com,zoho.com,zoho.eu,zoho.in,zoho.com.au,zohocloud.ca,github.com,githubusercontent.com,pagerduty.com,slack.com,telegram.org,pushover.net,openai.com,anthropic.com,openrouter.ai,portkey.ai,googleapis.com,ollama.com,okta.com,oktapreview.com,microsoftonline.com,accounts.google.com,auth0.comandonelogin.com.
Find your key
1
Open the tab
As an organization admin, open Settings and select the Request Signing tab. Your
organization’s first key already exists: SRE Agent creates it with a new organization, or with
the first signed request of one that existed before request signing.
2
Read the key list
The Keys table lists each key id with its state: Signing (in use now), Pending until
a time, Verify-only until a time, Retired or Revoked. Key ids are public. The keys
are not.
3
Reveal the key
Select Reveal key on the key marked Signing. The key appears with a Copy button and
is cleared from the page when you leave the tab. Revealing a key is recorded in the audit log.
4
Install it in your verifier
Add the key id and the key to the verifier you chose below.
Check a signature
The Check a signature form answers whether a request your server received is genuine. Enter the Method, the Host header, the Request target (path and query, as received), the SRE-Agent-Signature header and, optionally, When it arrived as Unix seconds or an ISO 8601 time, then select Check. The answer is about your organization’s keys only.Where to verify
Verify at the first hop that sees the request as the platform sent it: a CloudFront Function, Lambda@Edge, a Cloudflare Worker, nginx with njs or your application. A proxy that rewrites theHost header or re-encodes the path or query must either forward the originals (for example in X-Forwarded-Host) or run behind the verifier.
An edge that cannot read the body can still check the signature over the request line. Compare the body to b where you can read it.
To refuse a replay, keep the nonces you saw for 300 seconds. A retry always carries a new nonce, so a legitimate retry is never refused for it.
Roll it out
Log the verdict for a week before you refuse anything. During a deploy of the platform, the previous version keeps sending unsigned requests for a few minutes, and a key rotation changes the key id in use. Allow a clock skew of 300 seconds either way and run NTP. If the platform cannot read your key for a moment, it sends the request unsigned rather than not sending it, so keep logging unsigned requests after you start refusing bad signatures.Rotate or revoke a key
1
Create the new key
On the Request Signing tab, choose a delay next to Rotate: start signing with a new key
after (Now, 1 hour, 24 hours, 3 days or 7 days; 24 hours is the default)
and select Rotate key. A new key is created and waits as Pending until the delay ends.
With Now there is no pending period: the new key signs at once, and a verifier that refuses
bad signatures refuses requests until you install it. Only one key can be pending at a time.
2
Install it
Select Reveal key on the new key (Pending, or Signing if you chose Now) and add
its key id and key to your verifier, which then accepts both ids.
3
Let it take over
At the end of the delay, or earlier with Start signing with the new key now, the platform
signs with the new key and the old id stops appearing in requests. Cancel pending key
discards a pending key that has not signed anything.
4
Remove the old key
The old key stays valid for verification for seven days after that, shown as Verify-only
until, then it is retired. Remove it from your verifier at any time after the new key signs.
The canonical string
The signature covers nine lines joined with a line feed (\n), with no trailing newline, in UTF-8:
METHODis upper case.hostis theHostthe receiver sees, lower case, with:portonly when the port is not the scheme’s default (80 for http, 443 for https) and an IPv6 literal in brackets. A request relayed through a forwarder is signed with the authority as your configured URL writes it, so a URL that spells out:443or:80is signed, and arrives, with that port.pathis the request target’s path exactly as sent, still percent-encoded,/when empty.queryis everything after the first?exactly as sent, without the?, empty when there is none. It is not sorted or re-encoded. Compare what you received:$request_uriin nginx,req.originalUrlin Express,argsin a WAF log.bis the same value as the header’sb.
Test vectors
Use the keysrsk_AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8 (the base64url of the bytes 0 to 31), the key id k_0123456789abcdef, t=1791640800 (2026-10-10 14:00:00 UTC) and the nonce AAECAwQFBgcICQoLDA0ODw (the bytes 0 to 15). Check your verifier against both vectors before any traffic arrives. Changing any one of the method, host, path, query, body, t, n or kid must make it fail.
Verify in code
SRE Agent’s own tests run every snippet below against exactly these vectors.Node
Express or any framework that exposes the raw request target and body.Python
Go
Standard library only.Verify at the edge
nginx with njs
Load the module withjs_import sreagent from conf.d/nginx-sre-agent.js; and js_set $sre_agent_verdict sreagent.verdict;, and set $sre_agent_keys to kid=key pairs separated by spaces, from an included file. Log $sre_agent_verdict first. Refuse with if ($sre_agent_verdict != ok) { return 403; } once the log is clean.
CloudFront Function
Runtimecloudfront-js-2.0, with a KeyValueStore associated to the function that holds kid -> key. The function adds its verdict as an x-sre-agent-verdict header for your origin to log and refuses nothing. A viewer-request event carries no body, so the function leaves b to the origin.
CloudFront hands the function a parsed query string rather than the one that was sent. Measured on a live distribution: the values arrive still percent-encoded (%20, +, %2B and %C3%A9 are passed as sent), the values of a repeated name keep their order, and the order of different names is not kept (a=1&b=2&c=3 reached the function as b, a, c). So the function verifies a request with no query or with one parameter name exactly, and answers unverifiable_query, never bad_signature, for a query with two or more names. Enforce in Lambda@Edge (whose request.querystring is the raw string) or in your application when your requests carry such queries, and treat an unverifiable_query verdict as a request to check further in, not as a forgery.
Check a request from your logs
To check a request after it arrived, your logs must hold everything the signature covers: theSRE-Agent-Signature value verbatim, the method, the Host, the raw path and query, and the time it arrived. Paste those into Check a signature on the Request Signing tab, or run them through a verifier above.
Plain http
A signature on a plain-http request can be read on the path. It is bound to its host, path, query, method and body and to five minutes, and it carries no key, but use https wherever you can.Related
- Connect your data: the data sources whose reads are signed.
- Monitor endpoints with synthetic checks: the checks that carry the header.
- Manage people and roles: who can open Settings.