Skip to content

Instantly share code, notes, and snippets.

@krish7919
Last active August 15, 2022 03:50
Show Gist options
  • Save krish7919/44d56dd8a77f3dee94d06b6f1662a8b4 to your computer and use it in GitHub Desktop.
Save krish7919/44d56dd8a77f3dee94d06b6f1662a8b4 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
set -e
set -o nounset
# Summary:
# This script enables creation of the `iam_request_headers` for AWS Auth with
# Hashicorp Vault.
# It will be easy to remove the parts to do with Vault and just use the script
# to create the AWS SignatureV4 process.
# Ref:
# https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html
# https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
# https://czak.pl/2015/09/15/s3-rest-api-with-curl.html
# Path to OpenSSL version >1.0.0
OPENSSL=openssl
# Define our configuration
method="POST"
service="sts"
content="Action=GetCallerIdentity&Version=2011-06-15"
access_key="$(aws configure get default.aws_access_key_id)"
secret_key="$(aws configure get default.aws_secret_access_key)"
session_key="$(aws configure get default.aws_session_token)"
region="$(aws configure get default.region)"
host="${service}.${region}.amazonaws.com"
date="$(date -u +%Y%m%d)"
vault_header_value="<my custom vault header value (configured already in vault)>"
# Step 1: Form the canonical request
amz_date="$(date -u +${date}T%H%M%SZ)"
content_length="$(printf "%s" "${content}" | wc -m | sed 's/ //g')"
canonical_uri="/"
canonical_query_string=""
signed_headers="content-length;content-type;host;x-amz-date;x-amz-security-token;x-vault-aws-iam-server-id"
content_type="application/x-www-form-urlencoded; charset=utf-8"
hashed_payload="$(printf "%s" "${content}" | OPENSSL dgst -sha256)"
canonical_headers="$(printf "content-length:%s\ncontent-type:%s\nhost:%s\n" \
"${content_length}" \
"${content_type}" \
"${host}" \
)"
canonical_headers="$(printf "%s\nx-amz-date:%s\nx-amz-security-token:%s\n" \
"${canonical_headers}" \
"${amz_date}" \
"${session_key}" \
)"
canonical_headers="$(printf "%s\nx-vault-aws-iam-server-id:%s\n" \
"${canonical_headers}" \
"${vault_header_value}" \
)"
canonical_request="$(printf "%s\n%s\n%s\n%s\n\n%s\n%s" \
"${method}" \
"${canonical_uri}" \
"${canonical_query_string}" \
"${canonical_headers}" \
"${signed_headers}" \
"${hashed_payload}" \
)"
# Debug print to compare bytes: printf "%s" "${canonical_request}" | xxd -p
hashed_canonical_request="$(printf "%s" "${canonical_request}" | OPENSSL dgst -sha256)"
# Step 2: Form the string to sign
scope="${date}/${region}/${service}/aws4_request"
string_to_sign="$(printf "%s\n%s\n%s\n%s" \
"AWS4-HMAC-SHA256" \
"${amz_date}" \
"${scope}" \
"${hashed_canonical_request}" \
)"
# Step 3: Form the signature
function hmac_sha256_hexdigest {
key="${1}"
data="${2}"
# default is hex, but we specify it explicitly here
printf "%s" "${data}" | OPENSSL dgst -hex -sha256 -mac HMAC -macopt "hexkey:${key}" | sed 's/^.* //'
}
function hmac_sha256_digest {
key="${1}"
data="${2}"
printf "%s" "${data}" | OPENSSL dgst -binary -sha256 -mac HMAC -macopt "hexkey:${key}" | xxd -p -c 256
}
key="$(printf "AWS4${secret_key}" | xxd -p -c 256)"
dateKey="$(hmac_sha256_digest "${key}" "${date}")"
dateRegionKey="$(hmac_sha256_digest "${dateKey}" "${region}")"
dateRegionServiceKey="$(hmac_sha256_digest "${dateRegionKey}" "${service}")"
signingKey="$(hmac_sha256_digest "${dateRegionServiceKey}" "aws4_request")"
signedString="$(hmac_sha256_hexdigest "${signingKey}" "${string_to_sign}")"
# Step 4: Form the Authorization header
authorization_header="AWS4-HMAC-SHA256"
authorization_header="${authorization_header} Credential=${access_key}/${scope}"
authorization_header="${authorization_header}, SignedHeaders=${signed_headers}"
authorization_header="${authorization_header}, Signature=${signedString}"
iam_request_headers="$(jq -c -n \
--arg amz_date "${amz_date}" \
--arg authorization "${authorization_header}" \
--arg content_length "${content_length}" \
--arg content_type "${content_type}" \
--arg vault_header_value "${vault_header_value}" \
--arg session_key "${session_key}" \
--arg host "${host}" \
'{
"Content-Length": [$content_length],
"Content-Type": [$content_type],
"Host": [$host],
"X-Amz-Date": [$amz_date],
"X-Amz-Security-Token": [$session_key],
"X-Vault-AWS-IAM-Server-ID": [$vault_header_value],
"Authorization": [$authorization]
}' \
)"
iam_request_headers_b64="$(printf "%s\n" "${iam_request_headers}" | base64)"
# Send this to AWS STS to verify if it works. In that case, the request above
# needs to be modified to not contain the headers in the `[]`
#curl -v -X "POST" \
# --url "https://sts.eu-central-1.amazonaws.com/" \
# --header "Authorization: ${authorization_header}" \
# -H "X-Amz-Date: ${amz_date}" \
# -H "X-Amz-Security-Token: ${session_key}" \
# --data "${content}"
@adrianbartyczak
Copy link

This is kind of hard to read. Please take a look at mine: https://gist.github.com/adrianbartyczak/1a51c9fa2aae60d860ca0d70bbc686db

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment