-
-
Save inkblot/aed97400ee9cc741e09e0b00bbb4ce4c to your computer and use it in GitHub Desktop.
#!/bin/bash | |
_SELF="${0##*/}" | |
_HERE="$(dirname $(realpath ${0}))" | |
function aws_instance_profile_arn() { | |
curl -s http://169.254.169.254/2019-10-01/meta-data/iam/info | jq -r .InstanceProfileArn | |
} | |
function aws_instance_profile_name() { | |
aws_instance_profile_arn | sed -e 's/.*\///' | |
} | |
function aws_credentials() { | |
curl -s http://169.254.169.254/2019-10-01/meta-data/iam/security-credentials/$(aws_instance_profile_name) | |
} | |
function aws_access_key_id() { | |
aws_credentials | jq -r .AccessKeyId | |
} | |
function aws_secret_access_key() { | |
aws_credentials | jq -r .SecretAccessKey | |
} | |
function aws_session_token() { | |
aws_credentials | jq -r .Token | |
} | |
function aws_environment() { | |
cat <<EOS | |
export AWS_ACCESS_KEY_ID=$(aws_access_key_id) | |
export AWS_SECRET_ACCESS_KEY=$(aws_secret_access_key) | |
export AWS_SESSION_TOKEN=$(aws_session_token) | |
EOS | |
} | |
if [ "${_SELF}" = "aws-credentials.sh" ]; then | |
set -eu | |
aws_environment | |
fi |
#!/bin/bash | |
function AWS4_HMAC_SHA256() { | |
openssl dgst -sha256 -hex -mac HMAC -macopt "$1" 2>/dev/null | awk '{print $2}' | |
} | |
function AWS4_SHA256() { | |
openssl dgst -sha256 -hex 2>/dev/null | awk '{print $2}' | |
} | |
function AWS4_BASE64() { | |
openssl base64 -A | |
} | |
function AWS4_SIGN() { | |
local kSecret="AWS4$1" | |
local kDate=$(printf '%s' "$2" | AWS4_HMAC_SHA256 "key:${kSecret}") | |
local kRegion=$(printf '%s' "$3" | AWS4_HMAC_SHA256 "hexkey:${kDate}") | |
local kService=$(printf '%s' "$4" | AWS4_HMAC_SHA256 "hexkey:${kRegion}") | |
local kSigning=$(printf '%s' "aws4_request" | AWS4_HMAC_SHA256 "hexkey:${kService}") | |
local signedString=$(printf '%s' "$5" | AWS4_HMAC_SHA256 "hexkey:${kSigning}") | |
printf '%s' "${signedString}" | |
} |
#!/bin/bash | |
_SELF="${0##*/}" | |
_HERE="$(dirname $(realpath ${0}))" | |
source "${_HERE}/parse-url.sh" | |
source "${_HERE}/aws-credentials.sh" | |
source "${_HERE}/aws4-sign.sh" | |
function vault_iam_auth() { | |
local vault_role="$1" | |
local vault_addr="${2:-${VAULT_ADDR:-http://vault.example.internal:8200}}" | |
local vault_ca_cert="${3:-${VAULT_CA_CERT:-}}" | |
local aws_access_key_id="$(aws_access_key_id)" | |
local aws_secret_access_key="$(aws_secret_access_key)" | |
local aws_session_token="$(aws_session_token)" | |
local vault_host=$(parse_url "${vault_addr}" | jq -r .host) | |
local auth_type="AWS4-HMAC-SHA256" | |
local amz_date=$(TZ=Z date +%Y%m%dT%H%M%SZ) | |
local content_type="application/x-www-form-urlencoded charset=utf-8" | |
local iam_request_body="Action=GetCallerIdentity&Version=2011-06-15" | |
local iam_request_host="sts.amazonaws.com" | |
local iam_request_url="https://${iam_request_host}/" | |
local signed_headers="content-type;host;x-amz-date;x-amz-security-token;x-vault-aws-iam-server-id" | |
local canonical_request="$(cat <<EOR | |
POST | |
/ | |
content-type:${content_type} | |
host:${iam_request_host} | |
x-amz-date:${amz_date} | |
x-amz-security-token:${aws_session_token} | |
x-vault-aws-iam-server-id:${vault_host} | |
${signed_headers} | |
$(printf '%s' "${iam_request_body}" | AWS4_SHA256) | |
EOR | |
)" | |
local credential_scope="${amz_date:0:8}/us-east-1/sts/aws4_request" | |
local signed_string="$(cat <<EOS | |
${auth_type} | |
${amz_date} | |
${credential_scope} | |
$(printf '%s' "${canonical_request}" | AWS4_SHA256) | |
EOS | |
)" | |
#printf 'signed_string: $%s^\n\n' "${signed_string}" | |
local signature=$(AWS4_SIGN "${aws_secret_access_key}" "${amz_date:0:8}" "us-east-1" "sts" "${signed_string}") | |
local authorization="${auth_type} Credential=${aws_access_key_id}/${credential_scope}, SignedHeaders=${signed_headers}, Signature=${signature}" | |
local iam_request_headers="$(cat <<EOH | |
{ | |
"Content-Type": ["${content_type}"], | |
"Host": ["${iam_request_host}"], | |
"X-Amz-Date": ["${amz_date}"], | |
"X-Amz-Security-Token": ["${aws_session_token}"], | |
"X-Vault-AWS-IAM-Server-Id": ["${vault_host}"], | |
"Authorization": ["${authorization}"] | |
} | |
EOH | |
)" | |
local data="$(cat <<EOJ | |
{ | |
"role": "${vault_role}", | |
"iam_http_request_method": "POST", | |
"iam_request_url": "$(printf '%s' "${iam_request_url}" | AWS4_BASE64)", | |
"iam_request_body": "$(printf '%s' "${iam_request_body}" | AWS4_BASE64)", | |
"iam_request_headers": "$(printf '%s' "${iam_request_headers}" | AWS4_BASE64)" | |
} | |
EOJ | |
)" | |
curl -s ${vault_ca_cert:+--cacert ${vault_ca_cert}} --request POST --data "$(jq -c . <<<"${data}")" "${vault_addr}/v1/auth/aws/login" | |
} | |
if [ "${_SELF}" = "vault-iam-auth.sh" ]; then | |
set -eu | |
vault_iam_auth "$@" | |
fi |
I use these scripts to authenticate to vault using an EC2 instance's IAM role. To do this requires that you have a vault server. In this vault server the aws authentication backend must be mounted. In the aws backend there must be a backend role and policy bound to an IAM role. With these things in place, if you start an EC2 instance with the IAM role in its instance profile and put these shell scripts in the filesystem on the EC2 instance, you can authenticate to vault.
To get a vault token, log into the EC2 instance and run a command similar to vault_iam_auth "ec2-instance-role" "https://vault:8200" ${vault_ca_cert:-}
. The first parameter ec2-instance-role
is the name of the vault aws backend role. The second parameter is the URL of the vault server. vault_ca_cert
here can be set to the path of a file containing the CA certificate which has issued the server certificate for the vault server, or -
if you intend to pass this certificate via stdin. The stdout from this command is JSON produced by the authentication with vault. The token can be extracted from this JSON using the command jq -r .auth.client_token
. This command accepts the JSON on stdin. With this token, you can access vault in accordance with the policy that is bound to the aws backend role.
These scripts intentionally depend on very few tools. I think the complete list of commands that these scripts invoke is bash
, openssl
, curl
, jq
, cat
, sed
, awk
, dirname
, and realpath
.
How can it be used ?