Skip to content

Commit 8c0d0ce

Browse files
committed
evolve aws_china_mfa
1 parent aa013b3 commit 8c0d0ce

3 files changed

Lines changed: 162 additions & 52 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ A potpourri of sweet ingredients
88
## Tools
99

1010
<!-- keep-sorted start -->
11-
- **[aws_china_mfa](aws_china_mfa/)** - Authenticate to AWS China using MFA and export temporary session credentials in the current shell
11+
- **[aws_china_mfa](aws_china_mfa/)** - Authenticate to AWS China using MFA and export temporary session credentials
1212
- **[op_login_all](op_login_all/)** - Automatically log into all your 1Password accounts
1313
- **[pritunl_login](pritunl_login/)** - Connect to Pritunl VPN using credentials stored in 1Password
1414
- **[sd_world](sd_world/)** - Cross-platform full system upgrade script

aws_china_mfa/README.md

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# aws_china_mfa.sh
22

3-
A script to authenticate to AWS China using MFA and export temporary session credentials in the current shell.
3+
A script to authenticate to AWS China using MFA and export temporary session credentials.
44

55
## Usage
66

7-
Source the script (do not execute it directly):
7+
### Option 1: Source the script
88

99
```bash
1010
source ./aws_china_mfa.sh
@@ -16,8 +16,30 @@ Or with a custom AWS profile:
1616
source ./aws_china_mfa.sh my-china-profile
1717
```
1818

19+
### Option 2: Execute with eval
20+
21+
```bash
22+
eval "$(./aws_china_mfa.sh)"
23+
```
24+
25+
Or with a custom AWS profile:
26+
27+
```bash
28+
eval "$(./aws_china_mfa.sh my-china-profile)"
29+
```
30+
31+
### Option 3: Execute and copy/paste export commands
32+
33+
```bash
34+
./aws_china_mfa.sh
35+
```
36+
37+
The script will print export commands that you can copy and paste into your shell.
38+
1939
## Example Output
2040

41+
### Option 1: Source the script
42+
2143
```
2244
% source ./aws_china_mfa.sh
2345
Using AWS profile: china
@@ -28,10 +50,55 @@ Requesting session token...
2850
✓ Successfully authenticated to AWS China
2951
3052
Exported AWS credentials:
53+
3154
AWS_ACCESS_KEY_ID=AKIAWHEATLICIOUSPANCAK
3255
AWS_PROFILE=china
3356
AWS_SECRET_ACCESS_KEY=wSyrupyDeliciousSecretKeyForBreakfastDelight42
3457
AWS_SESSION_TOKEN=FwoGZXIvYXdzEBaaDCakesYrUpSWeetToKenArEDelIcIoUs...
3558
```
3659

37-
The script will prompt for your MFA token, retrieve temporary session credentials valid for 24 hours, and export them to your current shell session.
60+
### Option 2: Execute with eval
61+
62+
```
63+
% eval "$(./aws_china_mfa.sh)"
64+
Note: Script is being executed. To apply credentials, run:
65+
eval "$(./aws_china_mfa.sh china)"
66+
67+
Using AWS profile: china
68+
Enter the MFA token code for your AWS China account: 123456
69+
Retrieving MFA device ARN...
70+
Requesting session token...
71+
72+
✓ Successfully authenticated to AWS China
73+
74+
Copy and paste the export commands above to apply credentials.
75+
76+
export AWS_PROFILE='china'
77+
export AWS_ACCESS_KEY_ID='AKIAWHEATLICIOUSPANCAK'
78+
export AWS_SECRET_ACCESS_KEY='wSyrupyDeliciousSecretKeyForBreakfastDelight42'
79+
export AWS_SESSION_TOKEN='FwoGZXIvYXdzEBaaDCakesYrUpSWeetToKenArEDelIcIoUs...'
80+
```
81+
82+
### Option 3: Execute and copy/paste
83+
84+
```
85+
% ./aws_china_mfa.sh
86+
Note: Script is being executed. To apply credentials, run:
87+
eval "$(./aws_china_mfa.sh china)"
88+
89+
Using AWS profile: china
90+
Enter the MFA token code for your AWS China account: 123456
91+
Retrieving MFA device ARN...
92+
Requesting session token...
93+
94+
✓ Successfully authenticated to AWS China
95+
96+
Copy and paste the export commands above to apply credentials.
97+
98+
export AWS_PROFILE='china'
99+
export AWS_ACCESS_KEY_ID='AKIAWHEATLICIOUSPANCAK'
100+
export AWS_SECRET_ACCESS_KEY='wSyrupyDeliciousSecretKeyForBreakfastDelight42'
101+
export AWS_SESSION_TOKEN='FwoGZXIvYXdzEBaaDCakesYrUpSWeetToKenArEDelIcIoUs...'
102+
```
103+
104+
The script prompts for your MFA token, retrieves temporary session credentials valid for 24 hours, and exports them to your current shell session.

aws_china_mfa/aws_china_mfa.sh

Lines changed: 91 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
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

816
usage() {
917
cat << EOF
1018
Usage: 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
1423
POSITIONAL 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
2029
DESCRIPTION:
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
2537
PREREQUISITES:
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
3042
EXAMPLES:
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
3549
NOTES:
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
4053
EXIT CODES:
@@ -43,14 +56,6 @@ EXIT CODES:
4356
EOF
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-
5459
if [[ "${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+
80108
main() {
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

132176
main "$@"
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

Comments
 (0)