Skip to content

AWS SigV4 Plugin

This plugin adds an aws-sigv4 request-signing scheme to the credential proxy. It covers credentials AWS never receives directly: every AWS API request carries a signature computed with the secret access key, so plain placeholder substitution cannot broker them.

With this plugin, the agent’s AWS SDK signs requests normally using the placeholder credentials varlock injects into its environment. The proxy parses the region and service out of the inbound credential scope, strips the placeholder signature, and re-signs the request with the real keys at the network boundary. The secret access key never enters the agent’s environment, and the agent cannot produce a valid signature itself.

.env.schema
# @plugin(@varlock/aws-sigv4-plugin)
# ---
# @proxy(domain="*.amazonaws.com", transform={
# scheme="aws-sigv4", keyId=$AWS_ACCESS_KEY_ID,
# allowedServices=[bedrock, s3],
# })
AWS_SECRET_ACCESS_KEY=yourPreferredPlugin()
# @sensitive
AWS_ACCESS_KEY_ID=yourPreferredPlugin()

No SDK configuration is needed beyond pointing it at the proxy (which varlock proxy run does): the SDK signs with the placeholder credentials it sees, and one rule covers every AWS service and region the client talks to.

SigV4 is AWS’s protocol, but it is also the auth standard across the S3-compatible ecosystem, since those services are built to work with the AWS SDKs unchanged: Cloudflare R2, MinIO, Backblaze B2 (S3 API), DigitalOcean Spaces, Wasabi, IBM Cloud Object Storage, and Google Cloud Storage’s XML interop mode with HMAC keys (which signs with an s3 service scope). DynamoDB-compatible endpoints such as ScyllaDB Alternator work the same way.

The client is still an AWS SDK pointed at a custom endpoint, so the request carries a normal SigV4 credential scope, and the rule’s domain decides where the scheme applies:

.env.schema
# @plugin(@varlock/aws-sigv4-plugin)
# ---
# Broker Cloudflare R2 credentials the same way:
# @proxy(domain="myaccount.r2.cloudflarestorage.com", transform={
# scheme="aws-sigv4", keyId=$R2_ACCESS_KEY_ID,
# })
R2_SECRET_ACCESS_KEY=yourPreferredPlugin()
# @sensitive
R2_ACCESS_KEY_ID=yourPreferredPlugin()

The same limitations apply as for AWS itself. In particular, current AWS SDKs default requestChecksumCalculation to WHEN_SUPPORTED, which makes S3-style uploads use aws-chunked streaming payloads that the proxy cannot re-sign; set it to WHEN_REQUIRED on the client for those calls. See the limitations below.

OptionMeaning
keyId(required) Reference to the item holding the AWS access key id, e.g. keyId=$AWS_ACCESS_KEY_ID (travels in the Credential scope).
sessionTokenReference to the item holding a session token for temporary credentials, sent and signed as X-Amz-Security-Token.
allowedRegionsOnly sign requests whose scope names one of these regions, e.g. [us-east-1]. Omitted = any.
allowedServicesOnly sign requests whose scope names one of these services, e.g. [bedrock, s3]. Omitted = any.
  • A request without an inbound SigV4 signature is blocked with a message explaining the placeholder-signing setup (there is nothing to derive the region/service from).
  • Pre-signed URLs (X-Amz-Credential in the query string) are not supported and are blocked with a distinct message.
  • The payload hash covers the exact outbound body bytes, byte-for-byte (binary uploads included). If the client signed with the UNSIGNED-PAYLOAD sentinel, the proxy preserves it. aws-chunked streaming payloads (STREAMING-* sentinels, used by newer SDKs’ flexible checksums) cannot be re-signed and are blocked with a pointer at the SDK setting to disable them (requestChecksumCalculation: "WHEN_REQUIRED").
  • Signing uses the official AWS SDK v3 signer, including the S3-specific path-encoding rules.

See Request transforms for how transforms work in general.