Secrets
secrets: maps names to where their values come from. ${secret:name}
in a rule's set_header value, in sign credentials, or in an addon
endpoint's headers injects the value, so the client only ever holds a
placeholder. A reference anywhere else is a compile error.
secrets:
openai: { env: OPENAI_API_KEY }
gh: { file: /run/secrets/github_token } # one trailing newline is stripped
lease: { lease: true } # supplied by the control plane
rules:
- id: openai
when: host == "api.openai.com" and path starts_with "/v1/" and method == POST
then:
- set_header: { authorization: "Bearer ${secret:openai}" } # replaces whatever the client sent
- allow- Each secret has exactly one of
env,fileorlease: true. envandfileare read at startup and on reload. A missing or empty value stops roxy starting, or fails a reload.roxy checkandroxy rule testdo not read them.- Injected values are removed from the flow log and from captured headers.
- A
redirectsends the request, injected values included, to the new target. Make sure a rule that injects a secret cannot match a request that another rule redirects elsewhere.
Signing AWS requests
The sign action signs the forwarded request with AWS Signature Version
4, so a client holding placeholder credentials reaches AWS with a real
signature.
secrets:
aws_akid: { env: AWS_ACCESS_KEY_ID }
aws_sk: { env: AWS_SECRET_ACCESS_KEY }
aws_token: { env: AWS_SESSION_TOKEN }
rules:
- id: bedrock
when: host under "bedrock-runtime.eu-west-2.amazonaws.com" and scheme == "https"
then:
- sign:
aws_sigv4:
service: bedrock
region: eu-west-2
access_key_id: "${secret:aws_akid}"
secret_access_key: "${secret:aws_sk}"
session_token: "${secret:aws_token}" # optional
- allow- roxy signs the request as it is forwarded, after every other change the
rules make, wherever
signappears inthen. It removes any signature headers the client sent first. serviceis the AWS signing name, such asbedrock,s3orexecute-api. S3 services get S3's variant of the signature.- A request with a presigned URL (
X-Amz-Signaturein the query) is forwarded under the client's signature, not roxy's. The rule'shostandpathconditions still limit where it can go. - The body is buffered, up to
limits.max_sign_body_bytes(100 MiB), to hash it. A larger body is refused with413. For S3,unsigned_payload: trueskips the hash and streams the body. - If two matching rules both sign, the request is denied
(
sign_conflict).
Lease secrets
name: { lease: true } declares a secret that the control plane supplies
with the lease (node protocol). It
is held in memory only, never on disk. roxy run --config refuses a
config that declares one. When the control plane changes a secret, the
next request uses the new value, while an exchange in progress keeps the
value it started with.