Skip to content

Commit 06161ca

Browse files
hugbubbyclaude
andcommitted
ci: switch IAM policy from inline to managed, add RDS resource ARNs
The inline policy (2048-byte limit) was too small after adding the resource ARNs that rds:CreateDBInstance requires (subgrp, pg, og in addition to db). Switch to a customer managed policy (6144-byte limit). The script now: - Removes the legacy inline policy if present - Creates or version-updates a managed policy - Attaches it to the CI user Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 758c230 commit 06161ca

1 file changed

Lines changed: 73 additions & 13 deletions

File tree

src/aws/ci-iam/setup.sh

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
#
88
# 1. Verifies the AWS CLI is available and reads the account ID
99
# 2. Creates the openerrata-ci IAM user (skip if exists)
10-
# 3. Attaches a least-privilege inline policy scoped to the resources
10+
# 3. Creates or updates a customer managed policy scoped to the resources
1111
# Pulumi manages (S3 buckets, RDS instances, EC2 security groups,
12-
# IAM users for blob-storage writers)
12+
# IAM users for blob-storage writers) and attaches it
1313
# 4. Creates an access key (skip if one already exists)
1414
# 5. Prints credentials as JSON to stdout
1515
#
@@ -32,7 +32,6 @@
3232

3333
set -euo pipefail
3434

35-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
3635
IAM_USER="openerrata-ci"
3736
POLICY_NAME="openerrata-ci-pulumi-deploy"
3837

@@ -53,6 +52,8 @@ CALLER_IDENTITY="$(aws sts get-caller-identity --output json)"
5352
ACCOUNT_ID="$(echo "$CALLER_IDENTITY" | python3 -c "import sys,json; print(json.load(sys.stdin)['Account'])")"
5453
echo "Account ID: ${ACCOUNT_ID}" >&2
5554

55+
POLICY_ARN="arn:aws:iam::${ACCOUNT_ID}:policy/${POLICY_NAME}"
56+
5657
# ── 2. Create IAM user ────────────────────────────────────────────────
5758

5859
if aws iam get-user --user-name "$IAM_USER" &>/dev/null; then
@@ -66,12 +67,15 @@ else
6667
Key=purpose,Value=ci-deploy
6768
fi
6869

69-
# ── 3. Attach inline policy ───────────────────────────────────────────
70+
# ── 3. Create or update managed policy and attach ────────────────────
71+
72+
# Uses a managed policy (6144-byte limit) instead of an inline policy
73+
# (2048-byte limit) to accommodate the full set of resource ARNs that
74+
# AWS validates during RDS and EC2 operations.
7075

71-
echo "Attaching inline policy ${POLICY_NAME} ..." >&2
76+
echo "Preparing managed policy ${POLICY_NAME} ..." >&2
7277

73-
# The policy document uses $ACCOUNT_ID from the shell; all other $ signs
74-
# in ARN patterns are literal and must be escaped in the heredoc.
78+
# The policy document uses $ACCOUNT_ID from the shell.
7579
POLICY_DOCUMENT="$(cat <<EOF
7680
{
7781
"Version": "2012-10-17",
@@ -172,7 +176,12 @@ POLICY_DOCUMENT="$(cat <<EOF
172176
"rds:AddTagsToResource",
173177
"rds:RemoveTagsFromResource"
174178
],
175-
"Resource": "arn:aws:rds:*:${ACCOUNT_ID}:db:openerrata-*"
179+
"Resource": [
180+
"arn:aws:rds:*:${ACCOUNT_ID}:db:openerrata-*",
181+
"arn:aws:rds:*:${ACCOUNT_ID}:subgrp:*",
182+
"arn:aws:rds:*:${ACCOUNT_ID}:pg:*",
183+
"arn:aws:rds:*:${ACCOUNT_ID}:og:*"
184+
]
176185
},
177186
{
178187
"Sid": "RdsMutateSubnetGroups",
@@ -191,12 +200,63 @@ POLICY_DOCUMENT="$(cat <<EOF
191200
EOF
192201
)"
193202

194-
aws iam put-user-policy \
195-
--user-name "$IAM_USER" \
196-
--policy-name "$POLICY_NAME" \
197-
--policy-document "$POLICY_DOCUMENT"
203+
# Remove the old inline policy if it exists (migration from inline to managed).
204+
if aws iam get-user-policy --user-name "$IAM_USER" --policy-name "$POLICY_NAME" &>/dev/null; then
205+
echo "Removing legacy inline policy ..." >&2
206+
aws iam delete-user-policy --user-name "$IAM_USER" --policy-name "$POLICY_NAME"
207+
fi
208+
209+
# Create or update the managed policy.
210+
if aws iam get-policy --policy-arn "$POLICY_ARN" &>/dev/null; then
211+
echo "Updating existing managed policy ..." >&2
212+
213+
# Managed policies have a 5-version limit. Delete the oldest non-default
214+
# version before creating a new one to stay under the cap.
215+
OLD_VERSIONS="$(aws iam list-policy-versions --policy-arn "$POLICY_ARN" --output json \
216+
| python3 -c "
217+
import sys, json
218+
versions = json.load(sys.stdin)['Versions']
219+
non_default = [v['VersionId'] for v in versions if not v['IsDefaultVersion']]
220+
non_default.sort()
221+
print('\n'.join(non_default))
222+
")"
223+
224+
VERSION_COUNT="$(aws iam list-policy-versions --policy-arn "$POLICY_ARN" --output json \
225+
| python3 -c "import sys, json; print(len(json.load(sys.stdin)['Versions']))")"
226+
227+
if [ "$VERSION_COUNT" -ge 5 ] && [ -n "$OLD_VERSIONS" ]; then
228+
OLDEST="$(echo "$OLD_VERSIONS" | head -1)"
229+
echo "Deleting oldest policy version ${OLDEST} to make room ..." >&2
230+
aws iam delete-policy-version --policy-arn "$POLICY_ARN" --version-id "$OLDEST"
231+
fi
232+
233+
aws iam create-policy-version \
234+
--policy-arn "$POLICY_ARN" \
235+
--policy-document "$POLICY_DOCUMENT" \
236+
--set-as-default > /dev/null
237+
else
238+
echo "Creating managed policy ..." >&2
239+
aws iam create-policy \
240+
--policy-name "$POLICY_NAME" \
241+
--policy-document "$POLICY_DOCUMENT" \
242+
--description "Least-privilege policy for openerrata CI/CD Pulumi deployments" \
243+
--tags Key=managedBy,Value=bootstrap Key=purpose,Value=ci-deploy > /dev/null
244+
fi
245+
246+
# Ensure the policy is attached to the user.
247+
if ! aws iam list-attached-user-policies --user-name "$IAM_USER" --output json \
248+
| python3 -c "
249+
import sys, json
250+
policies = json.load(sys.stdin)['AttachedPolicies']
251+
sys.exit(0 if any(p['PolicyArn'] == '$POLICY_ARN' for p in policies) else 1)
252+
"; then
253+
echo "Attaching managed policy to ${IAM_USER} ..." >&2
254+
aws iam attach-user-policy --user-name "$IAM_USER" --policy-arn "$POLICY_ARN"
255+
else
256+
echo "Managed policy already attached to ${IAM_USER}." >&2
257+
fi
198258

199-
echo "Policy ${POLICY_NAME} attached." >&2
259+
echo "Policy ${POLICY_NAME} ready." >&2
200260

201261
# ── 4. Create access key ──────────────────────────────────────────────
202262

0 commit comments

Comments
 (0)