11#! /bin/bash
22# shellcheck disable=SC2317
3- set -euo pipefail
3+ set -uo pipefail
44
5- readonly DEFAULT_AWS_PROFILE=" china"
6- readonly SESSION_DURATION=86400
5+ DEFAULT_AWS_PROFILE=" ${DEFAULT_AWS_PROFILE:- china} "
6+ SESSION_DURATION=" ${SESSION_DURATION:- 86400} "
7+
8+ # Check if script is being sourced
9+ (return 0 2> /dev/null) && sourced=1 || sourced=0
10+
11+ # Only set -e when executed, not when sourced (to avoid exiting user's shell)
12+ if [[ $sourced -eq 0 ]]; then
13+ set -e
14+ fi
715
816usage () {
917 cat << EOF
1018Usage: source $0 [OPTIONS] [AWS_PROFILE]
19+ or: eval "\$ ($0 [OPTIONS] [AWS_PROFILE])"
1120
12- Authenticate to AWS China using MFA and export temporary session credentials in the current shell .
21+ Authenticate to AWS China using MFA and export temporary session credentials.
1322
1423POSITIONAL ARGUMENTS:
1524 AWS_PROFILE AWS profile name (default: $DEFAULT_AWS_PROFILE )
@@ -18,23 +27,27 @@ OPTIONS:
1827 -h, --help Show this help message and exit
1928
2029DESCRIPTION:
21- This script must be sourced (not executed) to export AWS session credentials
22- to your current shell environment. It prompts for an MFA token, retrieves
23- temporary session credentials, and exports them as environment variables.
30+ This script can be sourced or executed with eval to set AWS session credentials.
31+ It prompts for an MFA token, retrieves temporary session credentials, and
32+ exports them as environment variables.
33+
34+ When sourced: exports variables directly to your current shell
35+ When executed: prints export commands to stdout
2436
2537PREREQUISITES:
2638 - AWS CLI must be installed and configured
2739 - 'jq' must be installed for JSON parsing
2840 - AWS profile must have MFA device configured
2941
3042EXAMPLES:
31- source $0 Use default profile ($DEFAULT_AWS_PROFILE )
32- source $0 my-china-profile Use custom profile
33- source $0 --help Show this help
43+ source $0 Use default profile ($DEFAULT_AWS_PROFILE )
44+ source $0 my-china-profile Use custom profile
45+ eval "\$ ($0 )" Execute with eval (default profile)
46+ eval "\$ ($0 my-china-profile)" Execute with eval (custom profile)
47+ $0 --help Show this help
3448
3549NOTES:
3650 - Session credentials are valid for $SESSION_DURATION seconds (24 hours)
37- - This script must be sourced to export variables to your shell
3851 - Exported variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_PROFILE
3952
4053EXIT CODES:
@@ -43,14 +56,6 @@ EXIT CODES:
4356EOF
4457}
4558
46- # Check if script is being sourced
47- (return 0 2> /dev/null) && sourced=1 || sourced=0
48-
49- if [[ $sourced -eq 0 ]]; then
50- echo " Error: Do not invoke this script directly; instead, run 'source $0 '"
51- exit 1
52- fi
53-
5459if [[ " ${1:- } " == " -h" ]] || [[ " ${1:- } " == " --help" ]]; then
5560 usage
5661 return 0 2> /dev/null || exit 0
@@ -72,64 +77,102 @@ check_dependencies() {
7277 done
7378
7479 if [[ ${# missing_deps[@]} -gt 0 ]]; then
75- echo " Error: Missing required dependencies: ${missing_deps[*]} "
80+ echo " Error: Missing required dependencies: ${missing_deps[*]} " >&2
7681 return 1
7782 fi
7883}
7984
85+ set_credentials () {
86+ local mode=" $1 "
87+ local profile=" $2 "
88+ local access_key=" $3 "
89+ local secret_key=" $4 "
90+ local session_token=" $5 "
91+
92+ if [[ $mode -eq 1 ]]; then
93+ # Sourced mode: export directly
94+ export AWS_PROFILE=" $profile "
95+ export AWS_ACCESS_KEY_ID=" $access_key "
96+ export AWS_SECRET_ACCESS_KEY=" $secret_key "
97+ export AWS_SESSION_TOKEN=" $session_token "
98+ else
99+ # Execution mode: print export commands
100+ echo " "
101+ echo -e " export AWS_PROFILE='$profile '"
102+ echo -e " export AWS_ACCESS_KEY_ID='$access_key '"
103+ echo -e " export AWS_SECRET_ACCESS_KEY='$secret_key '"
104+ echo -e " export AWS_SESSION_TOKEN='$session_token '"
105+ fi
106+ }
107+
80108main () {
81109 check_dependencies
82110
83- export AWS_PROFILE=" ${1:- $DEFAULT_AWS_PROFILE } "
84- echo " Using AWS profile: $AWS_PROFILE "
111+ local aws_profile=" ${1:- $DEFAULT_AWS_PROFILE } "
112+
113+ if [[ $sourced -eq 0 ]]; then
114+ echo " Note: Script is being executed. To apply credentials, run:" >&2
115+ echo " eval \"\$ ($0 $aws_profile )\" " >&2
116+ echo " " >&2
117+ fi
118+
119+ echo " Using AWS profile: $aws_profile " >&2
120+ echo -n " Enter the MFA token code for your AWS China account: " >&2
85121
86- echo -n " Enter the MFA token code for your AWS China account: "
87122 read -r token
88123
89124 if [[ -z " $token " ]]; then
90- echo " Error: MFA token cannot be empty"
125+ echo " Error: MFA token cannot be empty" >&2
91126 return 1
92127 fi
93128
94- echo " Retrieving MFA device ARN..."
129+ echo " Retrieving MFA device ARN..." >&2
130+
95131 local mfa_arn
96- mfa_arn=" $( aws iam --profile " $AWS_PROFILE " get-user --output text --query User.Arn | sed ' s|:user/|:mfa/|' ) "
132+ mfa_arn=" $( aws iam --profile " $aws_profile " get-user --output text --query User.Arn 2> /dev/null | sed ' s|:user/|:mfa/|' ) "
97133
98134 if [[ -z " $mfa_arn " ]]; then
99- echo " Error: Could not retrieve MFA device ARN"
135+ echo " Error: Could not retrieve MFA device ARN" >&2
100136 return 1
101137 fi
102138
103- echo " Requesting session token..."
104- local credentials
105- credentials=" $( aws --profile " $AWS_PROFILE " sts get-session-token --serial-number " $mfa_arn " --token-code " $token " --duration-seconds $SESSION_DURATION ) "
139+ echo " Requesting session token..." >&2
106140
107- if [[ -z " $credentials " ]]; then
108- echo " Error: Failed to retrieve session token"
141+ local credentials
142+ if ! credentials=$( aws --profile " $aws_profile " sts get-session-token --serial-number " $mfa_arn " --token-code " $token " --duration-seconds " $SESSION_DURATION " 2>&1 ) ; then
143+ echo " " >&2
144+ echo " Error: Failed to retrieve session token." >&2
145+ echo " $credentials " >&2
109146 return 1
110147 fi
111148
112- AWS_ACCESS_KEY_ID=$( echo " $credentials " | jq -r ' .Credentials.AccessKeyId' )
113- AWS_SECRET_ACCESS_KEY=$( echo " $credentials " | jq -r ' .Credentials.SecretAccessKey' )
114- AWS_SESSION_TOKEN=$( echo " $credentials " | jq -r ' .Credentials.SessionToken' )
115-
116- export AWS_ACCESS_KEY_ID
117- export AWS_SECRET_ACCESS_KEY
118- export AWS_SESSION_TOKEN
149+ local access_key secret_key session_token
150+ access_key=$( echo " $credentials " | jq -r ' .Credentials.AccessKeyId' )
151+ secret_key=$( echo " $credentials " | jq -r ' .Credentials.SecretAccessKey' )
152+ session_token=$( echo " $credentials " | jq -r ' .Credentials.SessionToken' )
119153
120- if [[ -z " $AWS_SESSION_TOKEN " ]] || [[ " $AWS_SESSION_TOKEN " == " null" ]]; then
121- echo " Error: Failed to extract session token from credentials"
154+ if [[ -z " $session_token " ]] || [[ " $session_token " == " null" ]]; then
155+ echo " Error: Failed to extract session token from credentials" >&2
122156 return 1
123157 fi
124158
125- echo " "
126- echo " ✓ Successfully authenticated to AWS China"
127- echo " "
128- echo " Exported AWS credentials:"
129- env | grep ' ^AWS_' | sort
159+ set_credentials " $sourced " " $aws_profile " " $access_key " " $secret_key " " $session_token "
160+
161+ if [[ $sourced -eq 1 ]]; then
162+ echo " " >&2
163+ echo " ✓ Successfully authenticated to AWS China" >&2
164+ echo " " >&2
165+ echo " Exported AWS credentials:" >&2
166+ echo " " >&2
167+ env | grep ' ^AWS_' | sort >&2
168+ else
169+ echo " " >&2
170+ echo " ✓ Successfully authenticated to AWS China" >&2
171+ echo " " >&2
172+ echo " Copy and paste the export commands above to apply credentials." >&2
173+ fi
130174}
131175
132176main " $@ "
133177
134- # TODO #1: 1password integration: extract MFA directly from 1Password.
135- # TODO #2: make it work with both source and execution
178+ # TODO: 1password integration: extract MFA directly from 1Password.
0 commit comments