awslabs/aws-sigv4-proxy

This project signs and proxies HTTP requests with Sigv4

Go

468

195 commits

updated Sep 21, 2026

See the code

README

AWS SigV4 Proxy

The AWS SigV4 Proxy will sign incoming HTTP requests and forward them to the host specified in the Host header.

You can strip out arbirtary headers from the incoming request by using the -s option.

Getting Started

Build and run the Proxy

The proxy uses the default AWS SDK for Go credential search path:

* Environment variables.
* Shared credentials file.
* IAM role for Amazon EC2 or ECS task role

More information can be found in the [developer guide](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html)

docker build -t aws-sigv4-proxy .

# Env vars
docker run --rm -ti \
  -e 'AWS_ACCESS_KEY_ID=<YOUR ACCESS KEY ID>' \
  -e 'AWS_SECRET_ACCESS_KEY=<YOUR SECRET ACCESS KEY>' \
  -p 8080:8080 \
  aws-sigv4-proxy -v

# Shared Credentials (v1.10+)
# Note: Since v1.10, the image uses 'scratch' base which has no HOME directory.
# You must explicitly set AWS_SHARED_CREDENTIALS_FILE for the SDK to find credentials.
docker run --rm -ti \
  -v ~/.aws:/root/.aws \
  -p 8080:8080 \
  -e 'AWS_SHARED_CREDENTIALS_FILE=/root/.aws/credentials' \
  -e 'AWS_SDK_LOAD_CONFIG=true' \
  -e 'AWS_PROFILE=<SOME PROFILE>' \
  aws-sigv4-proxy -v

Configuration

When running the Proxy, the following flags can be used (none are required) : s", "

Flag (or short form)TypeDescriptionDefault
verbose or vBooleanEnable additional logging, implies all the log-* optionsFalse
log-failed-requestsBooleanLog 4xx and 5xx response bodyFalse
log-signing-processBooleanLog sigv4 signing processFalse
unsigned-payloadBooleanPrevent signing of the payload"False
portStringPort to serve http on8080
strip or sStringHeaders to strip from incoming requestNone
custom-headersStringComma-separated list of custom headers in key=value formatNone
duplicate-headersStringDuplicate headers to an X-Original- prefix nameNone
role-arnStringAmazon Resource Name (ARN) of the role to assumeNone
nameStringAWS Service to sign forNone
sign-hostStringHost to sign forNone
hostStringHost to proxy toNone
regionStringAWS region to sign forNone
upstream-url-schemeStringProtocol to proxy withhttps
no-verify-sslBooleanDisable peer SSL certificate validationFalse
transport.idle-conn-timeoutDurationIdle timeout to the upstream service40s
transport.max-idle-conns-per-hostIntMaximum idle (keep-alive) connections to keep per upstream host2

Examples

S3

# us-east-1
curl -s -H 'host: s3.amazonaws.com' http://localhost:8080/<BUCKET_NAME>

# other region
curl -s -H 'host: s3.<BUCKET_REGION>.amazonaws.com' http://localhost:8080/<BUCKET_NAME>

SQS

curl -s -H 'host: sqs.<AWS_REGION>.amazonaws.com' 'http://localhost:8080/<AWS_ACCOUNT_ID>/<QUEUE_NAME>?Action=SendMessage&MessageBody=example'

API Gateway

curl -H 'host: <REST_API_ID>.execute-api.<AWS_REGION>.amazonaws.com' http://localhost:8080/<STAGE>/<PATH>

Running the service and stripping out sigv2 authorization headers

docker run --rm -ti \
  -v ~/.aws:/root/.aws \
  -p 8080:8080 \
  -e 'AWS_SHARED_CREDENTIALS_FILE=/root/.aws/credentials' \
  -e 'AWS_SDK_LOAD_CONFIG=true' \
  -e 'AWS_PROFILE=<SOME PROFILE>' \
  aws-sigv4-proxy -v -s Authorization

Running the service and preserving the original Authorization header as X-Original-Authorization (useful because Authorization header will be overwritten.)

docker run --rm -ti \
  -v ~/.aws:/root/.aws \
  -p 8080:8080 \
  -e 'AWS_SHARED_CREDENTIALS_FILE=/root/.aws/credentials' \
  -e 'AWS_SDK_LOAD_CONFIG=true' \
  -e 'AWS_PROFILE=<SOME PROFILE>' \
  aws-sigv4-proxy -v --duplicate-headers Authorization

Running the service with Assume Role to use temporary credentials

docker run --rm -ti \
  -v ~/.aws:/root/.aws \
  -p 8080:8080 \
  -e 'AWS_SHARED_CREDENTIALS_FILE=/root/.aws/credentials' \
  -e 'AWS_SDK_LOAD_CONFIG=true' \
  -e 'AWS_PROFILE=<SOME PROFILE>' \
  aws-sigv4-proxy -v --role-arn <ARN OF ROLE TO ASSUME>

Include service name & region overrides when you notice errors like unable to determine service from host for API gateway, for example.

docker run --rm -ti \
  -v ~/.aws:/root/.aws \
  -p 8080:8080 \
  -e 'AWS_SHARED_CREDENTIALS_FILE=/root/.aws/credentials' \
  -e 'AWS_SDK_LOAD_CONFIG=true' \
  -e 'AWS_PROFILE=<SOME PROFILE>' \
  aws-sigv4-proxy -v --name execute-api --region us-east-1

OpenSearch

  • Access AWS OpenSearch domain, hosted in private subnet of AWS VPC, with access policy restricted to IAM role.

    Prepare connection (assume role, export AWS_PROFILE, run ssh tunnel):

    aws sts assume-role \
     --role-arn "arn:aws:iam::123456789012:role/example-role" \
     --role-session-name role-profile
    export AWS_PROFILE=role-profile
    
    ssh \
     -4 \
     -o BatchMode="yes" \
     -o StrictHostKeyChecking="no" \
     -o ProxyCommand="aws ssm start-session --target %h --region eu-west-1 --document-name AWS-StartSSHSession --parameters portNumber=%p" \
     -i /Users/user/.ssh/id_rsa ubuntu@i-bastion-host \
     -L 4443:vpc-private-domain-name.eu-west-1.es.amazonaws.com:443 \
     -N
    

    Finally, run proxy:

    docker run --rm -ti \
         -v ~/.aws:/root/.aws \
         --network=bridge \
         -p 8080:8080 \
         -e "AWS_SHARED_CREDENTIALS_FILE=/root/.aws/credentials" \
         -e "AWS_SDK_LOAD_CONFIG=true" \
         -e "AWS_PROFILE=role-profile" \
         aws-sigv4-proxy \
                 --verbose --log-failed-requests --log-signing-process --no-verify-ssl \
                 --name es --region eu-west-1 \
                 --host host.docker.internal:4443 \
                 --sign-host eu-west-1.es.amazonaws.com
    

    Access dashboard via http://localhost:8080/_dashboards/app/home#/tutorial_directory

Troubleshooting

Shared Credentials Not Found (v1.10+)

Starting with v1.10, the Docker image uses a scratch base image instead of alpine. The scratch image has no home directory and no HOME environment variable, which prevents the AWS SDK from automatically discovering shared credentials.

Symptoms:

  • Credential chain fails with messages about missing credentials
  • UserHomeNotFound errors
  • Requests fail with authentication errors despite mounting ~/.aws

Solution:

When using shared credentials with v1.10+, you must explicitly set AWS_SHARED_CREDENTIALS_FILE:

docker run --rm -ti \
  -v ~/.aws:/root/.aws \
  -p 8080:8080 \
  -e 'AWS_SHARED_CREDENTIALS_FILE=/root/.aws/credentials' \
  -e 'AWS_SDK_LOAD_CONFIG=true' \
  -e 'AWS_PROFILE=<SOME PROFILE>' \
  aws-sigv4-proxy -v

Alternatively, you can set HOME=/root to enable auto-discovery:

docker run --rm -ti \
  -v ~/.aws:/root/.aws \
  -p 8080:8080 \
  -e 'HOME=/root' \
  -e 'AWS_SDK_LOAD_CONFIG=true' \
  -e 'AWS_PROFILE=<SOME PROFILE>' \
  aws-sigv4-proxy -v

Reference

License

This library is licensed under the Apache 2.0 License.

Significant stargazers

Jaana Dogan

13,150 followers · starred Feb 2021

Lucas Käldström

876 followers · starred Jul 2026

YeonGyu-Kim

3,732 followers · starred Nov 2025

Ryu

122 followers · starred Aug 2026

awslabs/aws-sigv4-proxy

This project signs and proxies HTTP requests with Sigv4

Go

468

195 commits

updated Sep 21, 2026

See the code

README

AWS SigV4 Proxy

The AWS SigV4 Proxy will sign incoming HTTP requests and forward them to the host specified in the Host header.

You can strip out arbirtary headers from the incoming request by using the -s option.

Getting Started

Build and run the Proxy

The proxy uses the default AWS SDK for Go credential search path:

* Environment variables.
* Shared credentials file.
* IAM role for Amazon EC2 or ECS task role

More information can be found in the [developer guide](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html)

docker build -t aws-sigv4-proxy .

# Env vars
docker run --rm -ti \
  -e 'AWS_ACCESS_KEY_ID=<YOUR ACCESS KEY ID>' \
  -e 'AWS_SECRET_ACCESS_KEY=<YOUR SECRET ACCESS KEY>' \
  -p 8080:8080 \
  aws-sigv4-proxy -v

# Shared Credentials (v1.10+)
# Note: Since v1.10, the image uses 'scratch' base which has no HOME directory.
# You must explicitly set AWS_SHARED_CREDENTIALS_FILE for the SDK to find credentials.
docker run --rm -ti \
  -v ~/.aws:/root/.aws \
  -p 8080:8080 \
  -e 'AWS_SHARED_CREDENTIALS_FILE=/root/.aws/credentials' \
  -e 'AWS_SDK_LOAD_CONFIG=true' \
  -e 'AWS_PROFILE=<SOME PROFILE>' \
  aws-sigv4-proxy -v

Configuration

When running the Proxy, the following flags can be used (none are required) : s", "

Flag (or short form)TypeDescriptionDefault
verbose or vBooleanEnable additional logging, implies all the log-* optionsFalse
log-failed-requestsBooleanLog 4xx and 5xx response bodyFalse
log-signing-processBooleanLog sigv4 signing processFalse
unsigned-payloadBooleanPrevent signing of the payload"False
portStringPort to serve http on8080
strip or sStringHeaders to strip from incoming requestNone
custom-headersStringComma-separated list of custom headers in key=value formatNone
duplicate-headersStringDuplicate headers to an X-Original- prefix nameNone
role-arnStringAmazon Resource Name (ARN) of the role to assumeNone
nameStringAWS Service to sign forNone
sign-hostStringHost to sign forNone
hostStringHost to proxy toNone
regionStringAWS region to sign forNone
upstream-url-schemeStringProtocol to proxy withhttps
no-verify-sslBooleanDisable peer SSL certificate validationFalse
transport.idle-conn-timeoutDurationIdle timeout to the upstream service40s
transport.max-idle-conns-per-hostIntMaximum idle (keep-alive) connections to keep per upstream host2

Examples

S3

# us-east-1
curl -s -H 'host: s3.amazonaws.com' http://localhost:8080/<BUCKET_NAME>

# other region
curl -s -H 'host: s3.<BUCKET_REGION>.amazonaws.com' http://localhost:8080/<BUCKET_NAME>

SQS

curl -s -H 'host: sqs.<AWS_REGION>.amazonaws.com' 'http://localhost:8080/<AWS_ACCOUNT_ID>/<QUEUE_NAME>?Action=SendMessage&MessageBody=example'

API Gateway

curl -H 'host: <REST_API_ID>.execute-api.<AWS_REGION>.amazonaws.com' http://localhost:8080/<STAGE>/<PATH>

Running the service and stripping out sigv2 authorization headers

docker run --rm -ti \
  -v ~/.aws:/root/.aws \
  -p 8080:8080 \
  -e 'AWS_SHARED_CREDENTIALS_FILE=/root/.aws/credentials' \
  -e 'AWS_SDK_LOAD_CONFIG=true' \
  -e 'AWS_PROFILE=<SOME PROFILE>' \
  aws-sigv4-proxy -v -s Authorization

Running the service and preserving the original Authorization header as X-Original-Authorization (useful because Authorization header will be overwritten.)

docker run --rm -ti \
  -v ~/.aws:/root/.aws \
  -p 8080:8080 \
  -e 'AWS_SHARED_CREDENTIALS_FILE=/root/.aws/credentials' \
  -e 'AWS_SDK_LOAD_CONFIG=true' \
  -e 'AWS_PROFILE=<SOME PROFILE>' \
  aws-sigv4-proxy -v --duplicate-headers Authorization

Running the service with Assume Role to use temporary credentials

docker run --rm -ti \
  -v ~/.aws:/root/.aws \
  -p 8080:8080 \
  -e 'AWS_SHARED_CREDENTIALS_FILE=/root/.aws/credentials' \
  -e 'AWS_SDK_LOAD_CONFIG=true' \
  -e 'AWS_PROFILE=<SOME PROFILE>' \
  aws-sigv4-proxy -v --role-arn <ARN OF ROLE TO ASSUME>

Include service name & region overrides when you notice errors like unable to determine service from host for API gateway, for example.

docker run --rm -ti \
  -v ~/.aws:/root/.aws \
  -p 8080:8080 \
  -e 'AWS_SHARED_CREDENTIALS_FILE=/root/.aws/credentials' \
  -e 'AWS_SDK_LOAD_CONFIG=true' \
  -e 'AWS_PROFILE=<SOME PROFILE>' \
  aws-sigv4-proxy -v --name execute-api --region us-east-1

OpenSearch

  • Access AWS OpenSearch domain, hosted in private subnet of AWS VPC, with access policy restricted to IAM role.

    Prepare connection (assume role, export AWS_PROFILE, run ssh tunnel):

    aws sts assume-role \
     --role-arn "arn:aws:iam::123456789012:role/example-role" \
     --role-session-name role-profile
    export AWS_PROFILE=role-profile
    
    ssh \
     -4 \
     -o BatchMode="yes" \
     -o StrictHostKeyChecking="no" \
     -o ProxyCommand="aws ssm start-session --target %h --region eu-west-1 --document-name AWS-StartSSHSession --parameters portNumber=%p" \
     -i /Users/user/.ssh/id_rsa ubuntu@i-bastion-host \
     -L 4443:vpc-private-domain-name.eu-west-1.es.amazonaws.com:443 \
     -N
    

    Finally, run proxy:

    docker run --rm -ti \
         -v ~/.aws:/root/.aws \
         --network=bridge \
         -p 8080:8080 \
         -e "AWS_SHARED_CREDENTIALS_FILE=/root/.aws/credentials" \
         -e "AWS_SDK_LOAD_CONFIG=true" \
         -e "AWS_PROFILE=role-profile" \
         aws-sigv4-proxy \
                 --verbose --log-failed-requests --log-signing-process --no-verify-ssl \
                 --name es --region eu-west-1 \
                 --host host.docker.internal:4443 \
                 --sign-host eu-west-1.es.amazonaws.com
    

    Access dashboard via http://localhost:8080/_dashboards/app/home#/tutorial_directory

Troubleshooting

Shared Credentials Not Found (v1.10+)

Starting with v1.10, the Docker image uses a scratch base image instead of alpine. The scratch image has no home directory and no HOME environment variable, which prevents the AWS SDK from automatically discovering shared credentials.

Symptoms:

  • Credential chain fails with messages about missing credentials
  • UserHomeNotFound errors
  • Requests fail with authentication errors despite mounting ~/.aws

Solution:

When using shared credentials with v1.10+, you must explicitly set AWS_SHARED_CREDENTIALS_FILE:

docker run --rm -ti \
  -v ~/.aws:/root/.aws \
  -p 8080:8080 \
  -e 'AWS_SHARED_CREDENTIALS_FILE=/root/.aws/credentials' \
  -e 'AWS_SDK_LOAD_CONFIG=true' \
  -e 'AWS_PROFILE=<SOME PROFILE>' \
  aws-sigv4-proxy -v

Alternatively, you can set HOME=/root to enable auto-discovery:

docker run --rm -ti \
  -v ~/.aws:/root/.aws \
  -p 8080:8080 \
  -e 'HOME=/root' \
  -e 'AWS_SDK_LOAD_CONFIG=true' \
  -e 'AWS_PROFILE=<SOME PROFILE>' \
  aws-sigv4-proxy -v

Reference

License

This library is licensed under the Apache 2.0 License.

Significant stargazers

Jaana Dogan

13,150 followers · starred Feb 2021

Lucas Käldström

876 followers · starred Jul 2026

YeonGyu-Kim

3,732 followers · starred Nov 2025

Ryu

122 followers · starred Aug 2026

Languages

Go

98.9%

Dockerfile

1.1%