aws

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.

← Dumps