Skip to main content
Every request SRE Agent sends to an endpoint you configured carries an 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).
Remote synthetic locations (the regional probes) do not sign yet, and neither do self-hosted identity providers used for single sign-on or AI providers of the LangChain type.

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.com and ec2-<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.
These are where your own edge (a load balancer, a WAF, CloudFront) first sees the request, so a verifier there can check it. The China partition (.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.com and 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.com and onelogin.com.
A vendor’s API has no verifier you control, and the header would only tell the vendor which organization a request is for.

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.
The Where requests are signed table on the same tab lists the hosts your configuration sends requests to and what happens for each: signed, signed through one of your forwarders, not signed because it is AWS, not signed because it is a third-party service, or not signed yet. Put a verifier where a signed host’s requests first arrive.

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 the Host 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.
If a key leaks, select Revoke and replace now. The platform switches within a minute on every task and the old key never verifies again, so your verifier refuses requests until you install the new key.

The canonical string

The signature covers nine lines joined with a line feed (\n), with no trailing newline, in UTF-8:
  • METHOD is upper case.
  • host is the Host the receiver sees, lower case, with :port only 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 :443 or :80 is signed, and arrives, with that port.
  • path is the request target’s path exactly as sent, still percent-encoded, / when empty.
  • query is 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_uri in nginx, req.originalUrl in Express, args in a WAF log.
  • b is the same value as the header’s b.
The platform builds the final URL once and signs those exact bytes, so what you receive is what was signed. A request whose method, host, path or query holds a CR or LF is never signed.

Test vectors

Use the key srsk_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 with js_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

Runtime cloudfront-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: the SRE-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.