proposal-system/infra/deploy-role/create-deploy-role.sh
Adam Moussa 0f9d27fbf0
chore(infra): prep proposal-system for seahaven-prod deployment (#227)
* chore(infra): retarget prod to seahaven-prod account + OIDC deploy-role artifacts

Retarget the CDK prod env from mgmt (328440206208, now frozen for workloads) to the
dedicated seahaven-prod workload account (011934824531). proposal-system is the org's
first prod tenant. Hard-block env=staging (still targets frozen mgmt) in resolveConfig
until it is retargeted to seahaven-dev (710827005802). Add a WARN-only out-of-pipeline
deploy guard in bin/app.ts.

Add infra/deploy-role/: OIDC trust policy (sub scoped to
Sea-Haven-Industries/proposal-system:ref:refs/heads/main), least-privilege permissions
policy (AssumeRole on the verified cdk-hnb659fds bootstrap roles, deterministic site
bucket, account-scoped CloudFront invalidation), and an idempotent creation script.
Verified against live prod: bootstrap qualifier hnb659fds v32, OIDC provider present.
Passed GPT-4.1 cross-review (APPROVE) and workflow red-team (CLEAN). Role NOT yet created
— gated on /sh-security-review + the deploy go-ahead.

Docs: README + CLAUDE.md reflect the prod account and pipeline-only deploy.

* chore(infra): region-bound deploy-role DescribeStacks to us-east-1 (sh-security-review IAM-L2)

* feat(infra): Aurora prod backup retention 14d + window; prod-only CDK context

Bump Aurora automated-backup (PITR) retention 7->14d and set a preferred backup
window for the prod tenant. Dedicated AWS Backup vault + cross-account restore
test is a tracked follow-up (no org central-backup design exists yet). Prune the
stale mgmt-account AZ context; prod (011934824531) is the only deploy target.
2026-07-15 14:44:35 -04:00

71 lines
3.3 KiB
Bash
Executable file

#!/usr/bin/env bash
###############################################################################
# create-deploy-role.sh
#
# Creates / updates the GitHub Actions OIDC deploy role
# `githubdeploy-proposal-system` in AWS account 011934824531 (seahaven-prod),
# us-east-1, for the Sea-Haven-Industries/proposal-system repo (main branch).
#
# GATE — DO NOT EXECUTE until BOTH of the following have passed:
# 1. GPT-4.1 cross-family review (IAM policy / trust-policy change), via:
# python3 ~/Documents/repositories/seahaven/security-review/cross_review.py \
# "Review this IAM deploy-role trust+permissions for over-permission: <artifacts>"
# (STATUS 2026-07-14: RUN — verdict APPROVE, no BLOCK.)
# 2. /sh-security-review (deep agentic pass — IaC/IAM is a gated surface)
#
# This is an IAM/trust change: run BOTH gates and resolve every confirmed
# critical/high before running. This script mutates AWS; the artifact-authoring
# task did NOT run it. It is idempotent and safe to re-run.
#
# Resolved facts (Phase 0, read-only verification):
# Account : 011934824531 (seahaven-prod)
# Region : us-east-1
# Qualifier : hnb659fds (AWS CDK DEFAULT — no custom synthesizer needed)
# OIDC prov : arn:aws:iam::011934824531:oidc-provider/token.actions.githubusercontent.com
###############################################################################
set -euo pipefail
PROFILE="prod"
ROLE_NAME="githubdeploy-proposal-system"
POLICY_NAME="proposal-system-deploy"
ACCOUNT_ID="011934824531"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TRUST_POLICY="file://${SCRIPT_DIR}/trust-policy.json"
PERMS_POLICY="file://${SCRIPT_DIR}/permissions-policy.json"
echo "==> Verifying active account for profile '${PROFILE}'..."
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
echo "==> Ensuring role '${ROLE_NAME}' exists with the correct trust policy..."
if aws --profile "${PROFILE}" iam get-role --role-name "${ROLE_NAME}" >/dev/null 2>&1; then
echo " Role exists — updating assume-role (trust) policy."
aws --profile "${PROFILE}" iam update-assume-role-policy \
--role-name "${ROLE_NAME}" \
--policy-document "${TRUST_POLICY}"
else
echo " Role absent — creating."
aws --profile "${PROFILE}" iam create-role \
--role-name "${ROLE_NAME}" \
--assume-role-policy-document "${TRUST_POLICY}" \
--description "GitHub Actions OIDC deploy role for Sea-Haven-Industries/proposal-system (main)" \
--max-session-duration 3600 \
--tags Key=project,Value=proposal-system Key=managed-by,Value=create-deploy-role.sh
fi
echo "==> Putting inline permissions policy '${POLICY_NAME}' (create-or-replace)..."
aws --profile "${PROFILE}" iam put-role-policy \
--role-name "${ROLE_NAME}" \
--policy-name "${POLICY_NAME}" \
--policy-document "${PERMS_POLICY}"
ROLE_ARN="$(aws --profile "${PROFILE}" iam get-role --role-name "${ROLE_NAME}" \
--query Role.Arn --output text)"
echo "==> Done. Deploy role ready:"
echo " ${ROLE_ARN}"
echo " Configure the GitHub Actions workflow to assume this ARN via aws-actions/configure-aws-credentials."