Signing AWS SigV4 with curl and Postman
Curl and Postman both support AWS request signing — Sig V4 — with IAM credentials. Using them is often more convenient than setting up scripts with the SDKs.
This covers signed requests to an AWS endpoint with IAM user and role credentials, both assuming the role locally and via an EC2 instance profile.
Curl documentation shows how to sign as an IAM user. Role credentials work the same way if you add an x-amz-security-token header with the session token.
Format as an IAM user
curl --request GET "https://<SERVICE_DOMAIN_ENDPOINT>/" --user "<AWS_IAMUSER_ACCESS_KEY>:<AWS_IAMUSER_SECRET_KEY>" --aws-sigv4 "aws:amz:<REGION>:es"
Format as an IAM role
Or any other short-lived credentials:
curl --request GET "https://<SERVICE_ENDPOINT>/" --user "<AWS_IAMUSER_ACCESS_KEY>:<AWS_IAMUSER_SECRET_KEY>" --aws-sigv4 "aws:amz:<REGION>:es" -H "x-amz-security-token:<SESSION_TOKEN>"
Example 1. Assumed role credentials
Say a service has a resource policy that only accepts requests signed as IAM role curlRole:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "resource permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<AWS_ACCOUNT>:role/curlRole"
},
"Action": "es:ESHttp*",
"Resource": [
"arn:aws:es:<REGION>:<AWS_ACCOUNT>:<RESOURCE>/<RESOURCE_NAME>/*"
]
}
]
}
A signed curl request as that role needs three values: AccessKeyId, SecretAccessKey, and SessionToken. One way to get them is sts assume-role. The caller needs sts:AssumeRole on curlRole.
This stores those three fields from the assume-role output:
read -r AccessKeyId SecretAccessKey SessionToken <<< $(aws sts assume-role --role-arn <curlRole_ARN> --role-session-name curlTest | jq -r --argjson fields '["AccessKeyId","SecretAccessKey","SessionToken"]' '[.Credentials[$fields[]]] | join("\n")')
Then sign the request as curlRole:
curl --request GET "https://<SERVICE_DOMAIN_ENDPOINT>/" --user "${AccessKeyId}:${SecretAccessKey}" --aws-sigv4 "aws:amz:<REGION>:es" -H "x-amz-security-token:${SessionToken}"
Example 2. EC2 instance profile
From an instance, pull the profile credentials from instance metadata. First the role name:
TOKEN=`curl -sS -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
ROLE=`curl -sS -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/`
Then AccessKeyId, SecretAccessKey, and SessionToken:
ACCESS_KEY_ID=`curl -sS -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE | jq -r '.AccessKeyId'`
SECRET_ACCESS_KEY=`curl -sS -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE | jq -r '.SecretAccessKey'`
SESSION_TOKEN=`curl -sS -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE | jq -r '.Token'`
From there, build the request the same way as the assumed-role example above.
Postman
Same split: long-lived IAM user keys versus short-lived role sessions. Postman’s AWS Signature docs walk through the UI.
