From db9db0a51fa4964816b59b9e46fa28b3e0c9fca3 Mon Sep 17 00:00:00 2001 From: Arthur Coombes Date: Thu, 11 Sep 2025 09:27:17 +0100 Subject: [PATCH 1/5] *Parse Credentials file for useful values in the profile *use supplied mfa serial variable if it exists rather than guessing a value based on username --- aws_helper.sh | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/aws_helper.sh b/aws_helper.sh index e814802..488779d 100755 --- a/aws_helper.sh +++ b/aws_helper.sh @@ -178,6 +178,96 @@ EOF $GREP "^\[" $CREDENTIALS |$CUT -d ']' -f 1 | $TR -d '[' } +function __extract_config_from_file() { + # Check for tools and get most compatible + local GREP=$(which ggrep 2>/dev/null || which grep 2>/dev/null) + if [ -z "$GREP" ]; then + __aws_helper_log 'error' 'Cannot locate tool: grep'; + return 1 + fi + + local CUT=$(which cut 2>/dev/null) + if [ -z "$CUT" ]; then + __aws_helper_log 'error' 'Cannot locate tool: cut'; + return 1 + fi + +local AWK=$(which gawk 2>/dev/null || which awk 2>/dev/null ) + if [ -z "$AWK" ]; then + __aws_helper_log 'error' 'Cannot locate tool: awk'; + return 1 + fi + +local HEAD=$(which ghead 2>/dev/null || which head 2>/dev/null ) + if [ -z "$HEAD" ]; then + __aws_helper_log 'error' 'Cannot locate tool: head'; + return 1 + fi + +local SED=$(which gsed 2>/dev/null || which sed 2>/dev/null ) + if [ -z "$SED" ]; then + __aws_helper_log 'error' 'Cannot locate tool: sed'; + return 1 + fi + +local XARGS=$(which gxargs 2>/dev/null || which xargs 2>/dev/null ) + if [ -z "$XARGS" ]; then + __aws_helper_log 'error' 'Cannot locate tool: xargs'; + return 1 + fi + +# Default Config File +CREDENTIALS="$HOME/.aws/credentials" + +# Extract data from the config section +__header="[${AWS_PROFILE}]" + +# Find the first line in the section +local __start=$($GREP -nF -- "$header" "$CREDENTIALS" | $CUT -d: -f1 | $HEAD -n1) +if [ -z "$__start" ]; then + __aws_helper_log "Section '$header' not found" >&2 + exit 1 +fi + +# find the next section +local __next=$($AWK -v s="$__start" 'NR>s && /^\[/{print NR; exit}' "$CREDENTIALS") + +if [ -z "$__next" ]; then + # no following section: extract output from from start+1 to EOF + local __output=$($SED -n "$((i__start+1)),\$p" "$CREDENTIALS"| $SED -E 's/^[[:space:]]+//; s/[[:space:]]+$//; s/[[:space:]]*=[[:space:]]*/=/') +else + # extract between the two line numbers + local __output=$($SED -n "$((__start+1)),$((__next-1))p" "$CREDENTIALS"| $SED -E 's/^[[:space:]]+//; s/[[:space:]]+$//; s/[[:space:]]*=[[:space:]]*/=/') +fi + +#parse output into variables +while IFS='=' read -r __key __value; do + # skip empty or comment lines + [[ -z "$__key" || "$__key" =~ ^[[:space:]]*# ]] && continue + + # trim whitespace + __key=$(echo "$__key" | $XARGS) + __value=$(echo "$__value" | $XARGS) + + # assign variable + printf -v "$__key" '%s' "$__value" +done < <(echo "${__output}") + +# if there are variables we need we can export them as new ones as to not clobber any other references +if [[ -n $aws_access_key_id ]]; then + export __discovered_aws_access_key_id=${aws_access_key_id} +fi + +if [[ -n $aws_secret_access_key ]]; then + export __discovered_aws_secret_access_key=${aws_secret_access_key} +fi + +if [[ -n $mfa_serial ]]; then + export __discovered_mfa_serial=${mfa_serial} +fi + +} + ## # Get list of aliases in ./aws-helper/config ## @@ -462,8 +552,19 @@ EOF return 1; fi; +# Try and extract useful information from existing credentials file +__extract_config_from_file + + iam_user_name="$(echo ${AWS_ARN} | sed 's|[^/]*/||g')"; + +#If we've been told the serial use it + if [[ -n ${__discovered_mfa_serial} ]]; then + mfa_serial=${__discovered_mfa_serial} + else + # Fallback to old method mfa_serial="arn:aws:iam::${AWS_ACCOUNT_ID}:mfa/${iam_user_name}"; +fi if [ -z "${mfa_token}" ]; then __aws_helper_log 'info' 'Enter MFA token: ' '-n'; From ae67a7ed5fcdb16ed55f298700719fa62dac9cdd Mon Sep 17 00:00:00 2001 From: Arthur Coombes Date: Thu, 11 Sep 2025 09:46:18 +0100 Subject: [PATCH 2/5] Variable Fixes --- aws_helper.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws_helper.sh b/aws_helper.sh index 488779d..0187b47 100755 --- a/aws_helper.sh +++ b/aws_helper.sh @@ -223,9 +223,9 @@ CREDENTIALS="$HOME/.aws/credentials" __header="[${AWS_PROFILE}]" # Find the first line in the section -local __start=$($GREP -nF -- "$header" "$CREDENTIALS" | $CUT -d: -f1 | $HEAD -n1) +local __start=$($GREP -nF -- "$__header" "$CREDENTIALS" | $CUT -d: -f1 | $HEAD -n1) if [ -z "$__start" ]; then - __aws_helper_log "Section '$header' not found" >&2 + __aws_helper_log "Section '$__header' not found" >&2 exit 1 fi @@ -234,7 +234,7 @@ local __next=$($AWK -v s="$__start" 'NR>s && /^\[/{print NR; exit}' "$CREDENTIAL if [ -z "$__next" ]; then # no following section: extract output from from start+1 to EOF - local __output=$($SED -n "$((i__start+1)),\$p" "$CREDENTIALS"| $SED -E 's/^[[:space:]]+//; s/[[:space:]]+$//; s/[[:space:]]*=[[:space:]]*/=/') + local __output=$($SED -n "$((__start+1)),\$p" "$CREDENTIALS"| $SED -E 's/^[[:space:]]+//; s/[[:space:]]+$//; s/[[:space:]]*=[[:space:]]*/=/') else # extract between the two line numbers local __output=$($SED -n "$((__start+1)),$((__next-1))p" "$CREDENTIALS"| $SED -E 's/^[[:space:]]+//; s/[[:space:]]+$//; s/[[:space:]]*=[[:space:]]*/=/') From 803d9fa34a2bc66353626fcf9cfc5e2f1a37069b Mon Sep 17 00:00:00 2001 From: Arthur Coombes Date: Thu, 11 Sep 2025 09:49:00 +0100 Subject: [PATCH 3/5] Add some reporting around mfa_serial --- aws_helper.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/aws_helper.sh b/aws_helper.sh index 0187b47..c040277 100755 --- a/aws_helper.sh +++ b/aws_helper.sh @@ -565,6 +565,7 @@ __extract_config_from_file # Fallback to old method mfa_serial="arn:aws:iam::${AWS_ACCOUNT_ID}:mfa/${iam_user_name}"; fi +__aws_helper_log "Using mfa_serial : $mfa_serial" if [ -z "${mfa_token}" ]; then __aws_helper_log 'info' 'Enter MFA token: ' '-n'; From c5e15f103eca7a830ba6b312ce478ec1de8dee4e Mon Sep 17 00:00:00 2001 From: Arthur Coombes Date: Thu, 11 Sep 2025 12:23:44 +0100 Subject: [PATCH 4/5] Add another method to ascertain mfa_token --- aws_helper.sh | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/aws_helper.sh b/aws_helper.sh index c040277..0f5b3f9 100755 --- a/aws_helper.sh +++ b/aws_helper.sh @@ -253,6 +253,12 @@ while IFS='=' read -r __key __value; do printf -v "$__key" '%s' "$__value" done < <(echo "${__output}") +# clean variables + +unset __discovered_aws_access_key_id +unset __discovered_aws_secret_access_key +unset __discovered_mfa_serial + # if there are variables we need we can export them as new ones as to not clobber any other references if [[ -n $aws_access_key_id ]]; then export __discovered_aws_access_key_id=${aws_access_key_id} @@ -562,11 +568,20 @@ __extract_config_from_file if [[ -n ${__discovered_mfa_serial} ]]; then mfa_serial=${__discovered_mfa_serial} else - # Fallback to old method - mfa_serial="arn:aws:iam::${AWS_ACCOUNT_ID}:mfa/${iam_user_name}"; -fi + # Try to query "iam list-mfa-devices" if it is permitted without MFA + mfa_serial="$(aws iam list-mfa-devices --query 'MFADevices[*].SerialNumber' --output text)"; + if ! [ "${?}" -eq 0 ]; then + # this did not work - Fallback to old method + mfa_serial="arn:aws:iam::${AWS_ACCOUNT_ID}:mfa/${iam_user_name}"; + fi + fi __aws_helper_log "Using mfa_serial : $mfa_serial" +# Prevent Data leakage +unset __discovered_aws_access_key_id +unset __discovered_aws_secret_access_key +unset __discovered_mfa_serial + if [ -z "${mfa_token}" ]; then __aws_helper_log 'info' 'Enter MFA token: ' '-n'; read -r mfa_token; From f68b73fe84914b3e767488d5b4c30313f64a511e Mon Sep 17 00:00:00 2001 From: Arthur Coombes Date: Mon, 15 Sep 2025 09:58:29 +0100 Subject: [PATCH 5/5] Put in a better fix for MacOS date command, namely to use the gnu version --- aws_helper.sh | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/aws_helper.sh b/aws_helper.sh index 0f5b3f9..ff828e7 100755 --- a/aws_helper.sh +++ b/aws_helper.sh @@ -640,11 +640,20 @@ EOF local expiry_epoch; + # Select best date tool , work around weaknesses in MacOS date command + + local DATE=$(which gdate 2>/dev/null || which date 2>/dev/null) + if [ -z "$DATE" ]; then + __aws_helper_log 'error' 'Cannot locate tool: date'; + return 1 + fi + # Workaround for OSX date - if [ "$(uname)" == "Darwin" ]; then - expiry_epoch="$(date -j -f \"%Y-%m-%dT%H:%M:%SZ\" \"${AWS_MFA_EXPIRY}\" +%s)"; + if [ "$(uname)" == "Darwin" -a "$DATE" == "/bin/date" ] ; then + __aws_helper_log 'Please Install the Gnu Date tool' + exit 1 else - expiry_epoch="$(date -d ${AWS_MFA_EXPIRY} +%s)"; + expiry_epoch="$($DATE -d ${AWS_MFA_EXPIRY} +%s)"; fi local current_epoch="$(date -u +%s)";