Skip to content

Commit aa013b3

Browse files
committed
new script: aws_china_mfa
1 parent 18fbcfd commit aa013b3

3 files changed

Lines changed: 173 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +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
1112
- **[op_login_all](op_login_all/)** - Automatically log into all your 1Password accounts
1213
- **[pritunl_login](pritunl_login/)** - Connect to Pritunl VPN using credentials stored in 1Password
1314
- **[sd_world](sd_world/)** - Cross-platform full system upgrade script

aws_china_mfa/README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# aws_china_mfa.sh
2+
3+
A script to authenticate to AWS China using MFA and export temporary session credentials in the current shell.
4+
5+
## Usage
6+
7+
Source the script (do not execute it directly):
8+
9+
```bash
10+
source ./aws_china_mfa.sh
11+
```
12+
13+
Or with a custom AWS profile:
14+
15+
```bash
16+
source ./aws_china_mfa.sh my-china-profile
17+
```
18+
19+
## Example Output
20+
21+
```
22+
% source ./aws_china_mfa.sh
23+
Using AWS profile: china
24+
Enter the MFA token code for your AWS China account: 123456
25+
Retrieving MFA device ARN...
26+
Requesting session token...
27+
28+
✓ Successfully authenticated to AWS China
29+
30+
Exported AWS credentials:
31+
AWS_ACCESS_KEY_ID=AKIAWHEATLICIOUSPANCAK
32+
AWS_PROFILE=china
33+
AWS_SECRET_ACCESS_KEY=wSyrupyDeliciousSecretKeyForBreakfastDelight42
34+
AWS_SESSION_TOKEN=FwoGZXIvYXdzEBaaDCakesYrUpSWeetToKenArEDelIcIoUs...
35+
```
36+
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.

aws_china_mfa/aws_china_mfa.sh

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#!/bin/bash
2+
# shellcheck disable=SC2317
3+
set -euo pipefail
4+
5+
readonly DEFAULT_AWS_PROFILE="china"
6+
readonly SESSION_DURATION=86400
7+
8+
usage() {
9+
cat << EOF
10+
Usage: source $0 [OPTIONS] [AWS_PROFILE]
11+
12+
Authenticate to AWS China using MFA and export temporary session credentials in the current shell.
13+
14+
POSITIONAL ARGUMENTS:
15+
AWS_PROFILE AWS profile name (default: $DEFAULT_AWS_PROFILE)
16+
17+
OPTIONS:
18+
-h, --help Show this help message and exit
19+
20+
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.
24+
25+
PREREQUISITES:
26+
- AWS CLI must be installed and configured
27+
- 'jq' must be installed for JSON parsing
28+
- AWS profile must have MFA device configured
29+
30+
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
34+
35+
NOTES:
36+
- Session credentials are valid for $SESSION_DURATION seconds (24 hours)
37+
- This script must be sourced to export variables to your shell
38+
- Exported variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_PROFILE
39+
40+
EXIT CODES:
41+
0 Credentials successfully exported
42+
1 Error occurred during authentication
43+
EOF
44+
}
45+
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+
54+
if [[ "${1:-}" == "-h" ]] || [[ "${1:-}" == "--help" ]]; then
55+
usage
56+
return 0 2>/dev/null || exit 0
57+
fi
58+
59+
check_dependencies() {
60+
local required_deps=(
61+
# keep-sorted start
62+
"aws"
63+
"jq"
64+
# keep-sorted end
65+
)
66+
local missing_deps=()
67+
68+
for dep in "${required_deps[@]}"; do
69+
if ! command -v "$dep" &> /dev/null; then
70+
missing_deps+=("$dep")
71+
fi
72+
done
73+
74+
if [[ ${#missing_deps[@]} -gt 0 ]]; then
75+
echo "Error: Missing required dependencies: ${missing_deps[*]}"
76+
return 1
77+
fi
78+
}
79+
80+
main() {
81+
check_dependencies
82+
83+
export AWS_PROFILE="${1:-$DEFAULT_AWS_PROFILE}"
84+
echo "Using AWS profile: $AWS_PROFILE"
85+
86+
echo -n "Enter the MFA token code for your AWS China account: "
87+
read -r token
88+
89+
if [[ -z "$token" ]]; then
90+
echo "Error: MFA token cannot be empty"
91+
return 1
92+
fi
93+
94+
echo "Retrieving MFA device ARN..."
95+
local mfa_arn
96+
mfa_arn="$(aws iam --profile "$AWS_PROFILE" get-user --output text --query User.Arn | sed 's|:user/|:mfa/|')"
97+
98+
if [[ -z "$mfa_arn" ]]; then
99+
echo "Error: Could not retrieve MFA device ARN"
100+
return 1
101+
fi
102+
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)"
106+
107+
if [[ -z "$credentials" ]]; then
108+
echo "Error: Failed to retrieve session token"
109+
return 1
110+
fi
111+
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
119+
120+
if [[ -z "$AWS_SESSION_TOKEN" ]] || [[ "$AWS_SESSION_TOKEN" == "null" ]]; then
121+
echo "Error: Failed to extract session token from credentials"
122+
return 1
123+
fi
124+
125+
echo ""
126+
echo "✓ Successfully authenticated to AWS China"
127+
echo ""
128+
echo "Exported AWS credentials:"
129+
env | grep '^AWS_' | sort
130+
}
131+
132+
main "$@"
133+
134+
# TODO #1: 1password integration: extract MFA directly from 1Password.
135+
# TODO #2: make it work with both source and execution

0 commit comments

Comments
 (0)