procurement-ingest/infra/shoc-assessment-reader/teardown-assessment-reader.sh
Adam Moussa cf046089f4
iac(access): temporary shoc-assessment-dynamo-reader for Luby initial assessment (30-day, read-only) (#141)
* iac(access): temporary shoc-assessment-dynamo-reader role for Luby initial assessment

30-day, read-only (GetItem/Query/Scan/DescribeTable) cross-account role in
seahaven-prod trusting seahaven-external-dev, trust-policy hard expiry
2026-08-23. Steady state remains procurement-api + webhook; teardown script
included.

* harden(access): resolve sh-security-review findings on assessment reader

C1 (confirmed medium): DateLessThan expiry condition duplicated into both
permissions statements so in-flight sessions die at the deadline, not +1h.
C2 (confirmed medium): teardown now strips ALL inline/attached policies and
instance profiles before DeleteRole (kill-switch semantics restored,
idempotent), emergency-revocation section added to README.
Cheap hardenings: CDPATH-immune SCRIPT_DIR, MaxSessionDuration re-asserted
on update path, data-handling expectations documented.

* harden(access): address Open SWE review on #141

- Trust now requires ArnLike aws:PrincipalArn on the Identity Center role
  path (human SSO sessions only; string condition survives permission-set
  reprovisioning, unlike a role-ARN Principal pin)
- README extend instructions cover BOTH expiry sites (trust + permissions)
- Create script logs caller ARN + timestamp and validates the policy's KMS
  ARN against SSM /seahaven/dynamodb/cmk-arn before applying
2026-07-24 22:54:05 +00:00

61 lines
2.8 KiB
Bash
Executable file

#!/usr/bin/env bash
###############################################################################
# teardown-assessment-reader.sh
#
# Deletes the temporary `shoc-assessment-dynamo-reader` role in seahaven-prod
# (011934824531). Run once the Luby initial assessment is complete — and this
# is ALSO the emergency kill switch: a successful DeleteRole immediately
# invalidates all outstanding session credentials for the role.
#
# DeleteRole fails with DeleteConflict while ANY policy remains on the role
# (including the inline `AWSRevokeOlderSessions` policy the IAM console's
# "Revoke active sessions" button attaches), so this script enumerates and
# strips ALL inline policies, attached managed policies, and instance-profile
# memberships first. Idempotent: a rerun after the role is gone exits 0.
###############################################################################
set -euo pipefail
PROFILE="seahaven-prod"
ROLE_NAME="shoc-assessment-dynamo-reader"
ACCOUNT_ID="011934824531"
CALLER_ACCOUNT="$(aws --profile "${PROFILE}" sts get-caller-identity --query Account --output text)"
if [[ "${CALLER_ACCOUNT}" != "${ACCOUNT_ID}" ]]; then
echo "ERROR: profile '${PROFILE}' resolves to account ${CALLER_ACCOUNT}, expected ${ACCOUNT_ID}. Aborting." >&2
exit 1
fi
if ! aws --profile "${PROFILE}" iam get-role --role-name "${ROLE_NAME}" >/dev/null 2>&1; then
echo "==> Role '${ROLE_NAME}' already absent in ${ACCOUNT_ID} - nothing to do."
exit 0
fi
echo "==> Deleting ALL inline policies on '${ROLE_NAME}'..."
for POLICY in $(aws --profile "${PROFILE}" iam list-role-policies \
--role-name "${ROLE_NAME}" --query 'PolicyNames[]' --output text); do
echo " delete-role-policy ${POLICY}"
aws --profile "${PROFILE}" iam delete-role-policy \
--role-name "${ROLE_NAME}" --policy-name "${POLICY}"
done
echo "==> Detaching ALL managed policies on '${ROLE_NAME}'..."
for POLICY_ARN in $(aws --profile "${PROFILE}" iam list-attached-role-policies \
--role-name "${ROLE_NAME}" --query 'AttachedPolicies[].PolicyArn' --output text); do
echo " detach-role-policy ${POLICY_ARN}"
aws --profile "${PROFILE}" iam detach-role-policy \
--role-name "${ROLE_NAME}" --policy-arn "${POLICY_ARN}"
done
echo "==> Removing '${ROLE_NAME}' from any instance profiles..."
for IP in $(aws --profile "${PROFILE}" iam list-instance-profiles-for-role \
--role-name "${ROLE_NAME}" --query 'InstanceProfiles[].InstanceProfileName' --output text); do
echo " remove-role-from-instance-profile ${IP}"
aws --profile "${PROFILE}" iam remove-role-from-instance-profile \
--instance-profile-name "${IP}" --role-name "${ROLE_NAME}"
done
echo "==> Deleting role '${ROLE_NAME}' (this invalidates all outstanding sessions)..."
aws --profile "${PROFILE}" iam delete-role --role-name "${ROLE_NAME}"
echo "==> Done. ${ROLE_NAME} removed from ${ACCOUNT_ID}; all live sessions are dead."