c19cc68d15
Nova Slides Render / render (push) Failing after 14m19s
---ci--- project: acdl phase: 2 milestone: v1.29 status: complete ---/ci---
90 lines
3.5 KiB
Bash
Executable File
90 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# scripts/rotate_spike_key.sh - rotate the nova-spike-runner IAM access key.
|
|
#
|
|
# Uses the bootstrap root key (NOVA_BOOTSTRAP_AWS_*
|
|
# fallback) from the env to:
|
|
# 1. List nova-spike-runner's access keys.
|
|
# 2. Create a new key.
|
|
# 3. Write the new key to gitignored .env.secrets (chmod 600).
|
|
# 4. Deactivate + delete the old key(s).
|
|
#
|
|
# Idempotent: re-running always ends with exactly 1 active key for the user.
|
|
# Does NOT rotate the bootstrap root key (D-034 closure = manual user step).
|
|
#
|
|
# Spike scope (D-039): the spike user key is per-run-rotated; real OIDC is
|
|
# v1.2.
|
|
# Nova rebrand (P4, REQ-163): IAM user renamed acdl-spike-runner →
|
|
# nova-spike-runner.
|
|
# D-232 (v1.29): the forge Actions secret-store upload was dev-forge-only
|
|
# and has been removed with the forge-parity retirement. The rotated key
|
|
# is written to .env.secrets only; the consumer's deploy reads it from
|
|
# there.
|
|
set -euo pipefail
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
cd "$ROOT"
|
|
ENV_FILE="$ROOT/.env.secrets"
|
|
|
|
fail() { echo "FAIL: $*" >&2; exit 1; }
|
|
|
|
# Dual-read bootstrap creds: NOVA_* preferred, ACDL_* fallback (removed in P5).
|
|
: "${NOVA_BOOTSTRAP_AWS_ACCESS_KEY_ID:?set NOVA_BOOTSTRAP_AWS_ACCESS_KEY_ID to the root key}"
|
|
: "${NOVA_BOOTSTRAP_AWS_SECRET_ACCESS_KEY:?set NOVA_BOOTSTRAP_AWS_SECRET_ACCESS_KEY to the root key}"
|
|
REGION="${AWS_DEFAULT_REGION:-us-east-1}"
|
|
USER_NAME="nova-spike-runner"
|
|
|
|
# Confirm .env.secrets is gitignored before writing to it.
|
|
git check-ignore -q "$ENV_FILE" || fail "$ENV_FILE is not gitignored — refusing to write the key"
|
|
|
|
python3 - <<'PY'
|
|
import os
|
|
import sys
|
|
import json
|
|
import boto3
|
|
|
|
region = os.environ.get("AWS_DEFAULT_REGION", "us-east-1")
|
|
user = "nova-spike-runner"
|
|
env_file = os.path.join(os.getcwd(), ".env.secrets")
|
|
|
|
# Dual-read bootstrap creds: NOVA_* preferred, ACDL_* fallback (G-106, removed in P5).
|
|
bootstrap_key = os.environ["NOVA_BOOTSTRAP_AWS_ACCESS_KEY_ID"]
|
|
bootstrap_secret = os.environ["NOVA_BOOTSTRAP_AWS_SECRET_ACCESS_KEY"]
|
|
|
|
session = boto3.Session(
|
|
aws_access_key_id=bootstrap_key,
|
|
aws_secret_access_key=bootstrap_secret,
|
|
region_name=region,
|
|
)
|
|
iam = session.client("iam")
|
|
|
|
# List current keys.
|
|
keys = iam.list_access_keys(UserName=user).get("AccessKeyMetadata", [])
|
|
active = [k for k in keys if k["Status"] == "Active"]
|
|
|
|
# Create a new key first (so the user always has a working key during rotation).
|
|
new = iam.create_access_key(UserName=user)["AccessKey"]
|
|
new_id = new["AccessKeyId"]
|
|
new_secret = new["SecretAccessKey"]
|
|
print(f"iam: created new key {new_id} for {user}", file=sys.stderr)
|
|
|
|
# Write the new key to gitignored .env.secrets (chmod 600).
|
|
# Nova rebrand (P2): keys are NOVA_*; the ACDL_* legacy keys are the
|
|
# dual-read fallback source until P5 (kept as comments in .env.secrets).
|
|
with open(env_file, "w") as fh:
|
|
fh.write(f"NOVA_AWS_ACCESS_KEY_ID={new_id}\n")
|
|
fh.write(f"NOVA_AWS_SECRET_ACCESS_KEY={new_secret}\n")
|
|
fh.write(f"AWS_DEFAULT_REGION={region}\n")
|
|
os.chmod(env_file, 0o600)
|
|
print(f"rotated key written to {env_file} (chmod 600)", file=sys.stderr)
|
|
|
|
# Deactivate + delete the old keys. The new key is already in .env.secrets
|
|
# so deactivating is safe (D-039 local-rotation contract).
|
|
for k in active:
|
|
old_id = k["AccessKeyId"]
|
|
if old_id == new_id:
|
|
continue
|
|
iam.update_access_key(UserName=user, AccessKeyId=old_id, Status="Inactive")
|
|
iam.delete_access_key(UserName=user, AccessKeyId=old_id)
|
|
print(f"iam: deactivated+deleted old key {old_id}", file=sys.stderr)
|
|
|
|
print(f"OK: {user} now has exactly 1 active key: {new_id}")
|
|
PY |