From 36555ccfc1b767d515f9ebc8dba7137c2c9d618d Mon Sep 17 00:00:00 2001 From: Michal Hybner Date: Thu, 16 Nov 2023 22:15:34 +0100 Subject: [PATCH] Add ECS task credentials support --- README.md | 8 +++++++- aws-curl | 35 ++++++++++++++++++++++++++++++----- ec2-import-creds | 2 +- ecs-import-creds | 14 ++++++++++++++ 4 files changed, 52 insertions(+), 7 deletions(-) mode change 100755 => 100644 aws-curl create mode 100644 ecs-import-creds diff --git a/README.md b/README.md index e2c386d..1fbe3b5 100644 --- a/README.md +++ b/README.md @@ -234,6 +234,7 @@ Wrapper recognizes these non-curl arguments: - `--region` - AWS region name, if can't be automatically detected from host or if not explicitly provided in `AWS_DEFAULT_REGION` environment variable - `--ec2-creds` - use attached to EC2 credentials (instance role) +- `--ecs-creds` - use attached to ECS credentials (task role) ### Response format @@ -307,10 +308,15 @@ including access key, secret key, session token and region. Just import from the shell as `source ec2-import-creds`. -Or you can use `--ec2-creds` options of `aws-cli` to get the same effect, but +Or you can use `--ec2-creds` option of `aws-curl` to get the same effect, but importing credentials once in beginning is faster than importing for every `aws-curl` invocation. +## ECS attached role + +When your service runs as ECS task you can import the attached credentials +using `source ecs-import-creds` or `--ecs-creds` option. + ## Platforms The script has been tested on bash in posix mode on macOS and Linux. It should diff --git a/aws-curl b/aws-curl old mode 100755 new mode 100644 index a52a873..5c40390 --- a/aws-curl +++ b/aws-curl @@ -1,7 +1,7 @@ #!/bin/sh # shellcheck disable=SC2155,SC2001 -VERSION="1.0.9" +VERSION="1.0.10" DATE_CMD="date" SED_CMD="sed" @@ -21,7 +21,7 @@ fi # safe url string ## urlsafe() { - echo "$1" | sed \ + echo "$1" | $SED_CMD \ -e 's!\x09!%09!g' \ -e 's!\x0A!%0A!g' \ -e 's!\x0B!%0B!g' \ @@ -336,7 +336,7 @@ sigv4_authorization_header() { } ## -# Extracts key value from pretty-printed JSON-like structure. +# Extracts key value from JSON-like structure. # Arguments: # $1 payload # $2 key name @@ -344,7 +344,7 @@ sigv4_authorization_header() { # key value ## get_key_value() { - echo "$1" | grep "$2" | cut -d ':' -f 2 | cut -d '"' -f 2 + echo "$1" | $SED_CMD -n -e "s/.*\"$2\": *\"\([^\"]*\)\".*/\1/p" } ## @@ -355,7 +355,7 @@ get_key_value() { # region without az suffix ## strip_az_suffix() { - echo "$1" | sed -e 's![a-z]$!!' + echo "$1" | $SED_CMD -e 's![a-z]$!!' } ## @@ -379,6 +379,21 @@ ec2_import_creds() { fi } +## +# Imports credentials attached to ECS task +## +ecs_import_creds() { + curl_opts="--silent --connect-timeout 1 --fail" + ecs_creds_url="http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" + credentials=$(curl $curl_opts "$ecs_creds_url") + + if [ -n "$credentials" ]; then + AWS_ACCESS_KEY_ID=$(get_key_value "$credentials" "AccessKeyId") + AWS_SECRET_ACCESS_KEY=$(get_key_value "$credentials" "SecretAccessKey") + AWS_SESSION_TOKEN=$(get_key_value "$credentials" "Token") + fi +} + ## # Show help ## @@ -405,6 +420,7 @@ CURL_VERBOSE="" AWS_REGION="" AWS_SERVICE="" EC2_CREDS="0" +ECS_CREDS="0" # read command line arguments while [ "$#" != 0 ]; do @@ -460,6 +476,10 @@ while [ "$#" != 0 ]; do shift EC2_CREDS="1" ;; + --ecs-creds ) + shift + ECS_CREDS="1" + ;; --data-ascii | --data-raw | --data-urlencode ) echo "Option $1 is not supported at this time." exit 1 @@ -500,6 +520,11 @@ if [ "$EC2_CREDS" = 1 ]; then ec2_import_creds fi +# import attached ecs credentials if enabled +if [ "$ECS_CREDS" = 1 ]; then + ecs_import_creds +fi + # check mandatory environment variables if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then echo "AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are not set." diff --git a/ec2-import-creds b/ec2-import-creds index bac8e9f..9ac6d3d 100644 --- a/ec2-import-creds +++ b/ec2-import-creds @@ -6,7 +6,7 @@ credentials=$([ -n "$attached_role_name" ] && curl -m 1 -s "http://169.254.169.2 availability_zone="$(curl -m 1 -s "http://169.254.169.254/latest/meta-data/placement/availability-zone")" get_key_value() { - echo "$1" | grep "$2" | cut -d ':' -f 2 | cut -d '"' -f 2 + echo "$1" | sed -n -e "s/.*\"$2\": *\"\([^\"]*\)\".*/\1/p" } strip_az_suffix() { diff --git a/ecs-import-creds b/ecs-import-creds new file mode 100644 index 0000000..675b6a3 --- /dev/null +++ b/ecs-import-creds @@ -0,0 +1,14 @@ +#!/bin/sh +# shellcheck disable=SC2155 + +credentials=$(curl -m 1 -s "http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") + +get_key_value() { + echo "$1" | sed -n -e "s/.*\"$2\": *\"\([^\"]*\)\".*/\1/p" +} + +if [ -n "$credentials" ]; then + export AWS_ACCESS_KEY_ID=$(get_key_value "$credentials" "AccessKeyId") + export AWS_SECRET_ACCESS_KEY=$(get_key_value "$credentials" "SecretAccessKey") + export AWS_SESSION_TOKEN=$(get_key_value "$credentials" "Token") +fi