-
Notifications
You must be signed in to change notification settings - Fork 0
/
action.yaml
195 lines (159 loc) · 6.2 KB
/
action.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
name: Configure AWS Profiles
description: Configures multiple OIDC AWS Role Sessions as AWS config profiles.
branding:
icon: 'cloud'
color: 'orange'
inputs:
profiles:
required: true
description: 'YAML mapping of profiles to configure.'
default-region:
required: false
description: 'Default AWS region to be used if not specified in a profile.'
default: 'us-west-2'
runs:
using: "composite"
steps:
- name: Get OIDC Token
shell: bash
env:
ACTIONS_ID_TOKEN_REQUEST_URL: ${{ env.ACTIONS_ID_TOKEN_REQUEST_URL }}
ACTIONS_ID_TOKEN_REQUEST_TOKEN: ${{ env.ACTIONS_ID_TOKEN_REQUEST_TOKEN }}
run: |
# Ensure the 'id-token: write' permission is set in your workflow
if [ -z "$ACTIONS_ID_TOKEN_REQUEST_TOKEN" ]; then
echo "Error: ACTIONS_ID_TOKEN_REQUEST_TOKEN is not set. Ensure 'id-token: write' permission is granted."
exit 1
fi
# Add audience parameter to the request URL
TOKEN_REQUEST_URL="${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=sts.amazonaws.com"
# Request the OIDC token
OIDC_TOKEN=$(curl -sS "$TOKEN_REQUEST_URL" -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" | jq -r '.value')
if [ -z "$OIDC_TOKEN" ]; then
echo "Error: Failed to retrieve OIDC token."
exit 1
fi
echo "OIDC_TOKEN=$OIDC_TOKEN" >> $GITHUB_ENV
- name: Ensure AWS Config Directory Exists
shell: bash
run: |
mkdir -p ~/.aws
- name: Setup AWS Profiles
shell: bash
env:
OIDC_TOKEN: ${{ env.OIDC_TOKEN }}
run: |
set -euo pipefail
echo "${{ inputs.profiles }}" > profiles.yaml
PROFILE_NAMES=$(yq e 'keys | .[]' profiles.yaml)
# Define lock file
LOCK_FILE="/tmp/aws_credentials.lock"
# Array to hold PIDs of background jobs
pids=()
# Function to configure a single profile
configure_profile() {
local PROFILE_NAME=$1
local LOCK_FILE=$2
REGION=$(yq e ".\"$PROFILE_NAME\".region // \"${{ inputs.default-region }}\"" profiles.yaml)
ROLE_ARN=$(yq e ".\"$PROFILE_NAME\".role-arn" profiles.yaml)
if [ -z "$ROLE_ARN" ]; then
echo "Error: role-arn is not specified for profile $PROFILE_NAME" >&2
exit 1
fi
echo "Configuring profile $PROFILE_NAME with region $REGION and role $ROLE_ARN"
# Assume role using AWS CLI with OIDC
CREDENTIALS=$(aws sts assume-role-with-web-identity \
--role-arn "$ROLE_ARN" \
--role-session-name "$PROFILE_NAME" \
--web-identity-token "$OIDC_TOKEN" \
--duration-seconds 3600 \
--region "$REGION" \
--output json 2>/dev/null)
if [ $? -ne 0 ] || [ -z "$CREDENTIALS" ]; then
echo "Error: Failed to assume role $ROLE_ARN for profile $PROFILE_NAME" >&2
exit 1
fi
# Extract credentials
AWS_ACCESS_KEY_ID=$(echo "$CREDENTIALS" | jq -r '.Credentials.AccessKeyId')
AWS_SECRET_ACCESS_KEY=$(echo "$CREDENTIALS" | jq -r '.Credentials.SecretAccessKey')
AWS_SESSION_TOKEN=$(echo "$CREDENTIALS" | jq -r '.Credentials.SessionToken')
# Acquire file lock before writing to shared files
{
flock -x 200
# Write to ~/.aws/credentials
cat <<-EOF >> ~/.aws/credentials
[$PROFILE_NAME]
aws_access_key_id = $AWS_ACCESS_KEY_ID
aws_secret_access_key = $AWS_SECRET_ACCESS_KEY
aws_session_token = $AWS_SESSION_TOKEN
EOF
# Write to ~/.aws/config
cat <<-EOF >> ~/.aws/config
[profile $PROFILE_NAME]
region = $REGION
EOF
} 200>"$LOCK_FILE"
if [ $? -ne 0 ]; then
echo "Error: Failed to acquire lock for profile $PROFILE_NAME" >&2
exit 1
fi
echo "Successfully configured profile $PROFILE_NAME"
}
export -f configure_profile
# Iterate over profiles and configure them in parallel
for PROFILE_NAME in $PROFILE_NAMES; do
configure_profile "$PROFILE_NAME" "$LOCK_FILE" &
pids+=($!)
done
# Wait for all background jobs to finish and collect their exit statuses
exit_code=0
for pid in "${pids[@]}"; do
if ! wait "$pid"; then
echo "Error: A background job (PID $pid) failed." >&2
exit_code=1
fi
done
# Exit with non-zero code if any job failed
if [ "$exit_code" -ne 0 ]; then
echo "One or more profile configurations failed." >&2
exit 1
fi
- name: Verify AWS Profiles
shell: bash
run: |
set -euo pipefail
echo "${{ inputs.profiles }}" > profiles.yaml
PROFILE_NAMES=$(yq e 'keys | .[]' profiles.yaml)
# Array to hold PIDs of background jobs
pids=()
# Function to verify a single profile
verify_profile() {
local PROFILE_NAME=$1
REGION=$(yq e ".\"$PROFILE_NAME\".region // \"${{ inputs.default-region }}\"" profiles.yaml)
echo "Verifying profile $PROFILE_NAME in region $REGION"
# Verify credentials with explicit region
if ! aws sts get-caller-identity --profile "$PROFILE_NAME" --region "$REGION" >/dev/null 2>&1; then
echo "Error: Verification failed for profile $PROFILE_NAME" >&2
exit 1
fi
echo "Profile $PROFILE_NAME is valid"
}
export -f verify_profile
# Iterate over profiles and verify them in parallel
for PROFILE_NAME in $PROFILE_NAMES; do
verify_profile "$PROFILE_NAME" &
pids+=($!)
done
# Wait for all background jobs to finish and collect their exit statuses
exit_code=0
for pid in "${pids[@]}"; do
if ! wait "$pid"; then
echo "Error: A verification job (PID $pid) failed." >&2
exit_code=1
fi
done
# Exit with non-zero code if any job failed
if [ "$exit_code" -ne 0 ]; then
echo "One or more profile verifications failed." >&2
exit 1
fi