0fea29cdbb
---ci--- project: acdl phase: 12 milestone: v1.2 status: verify verdict: VERIFIED requirements: covered: [REQ-30] ---/ci--- Phase 12 plan-as-execute + verify. scripts/verify_phase12.sh green (22 assertions). All Wave 1 + Wave 2 tasks complete: - T-12.1: run_spike_*.sh -> run_platform.sh (D-048, --plan-only flag) - T-12.2: spike_runner_policy.json expanded (ECS + ECR + ELB + IAM + EC2) - T-12.3: idempotency documented in bootstrap scripts - T-12.4: P1-1 redacted (no live AWS key IDs in .ciagent/) - T-12.5: P1-B fixed (PERSONAS.md platform/registry -> modules-ir/registry.json) Subagent confirmed run_platform.sh --plan-only runs against real AWS, exit 0. Ready to ship v1.2.2.
80 lines
3.1 KiB
Python
80 lines
3.1 KiB
Python
"""Create the ACDL v1.1 spike IAM user + scoped inline policy + initial key.
|
|
|
|
Idempotent: skips user creation if the user exists; creates an initial
|
|
access key if none active exists. Prints the key to stdout for the
|
|
orchestrator to capture (NEVER committed):
|
|
ACDL_AWS_ACCESS_KEY_ID=<...>
|
|
ACDL_AWS_SECRET_ACCESS_KEY=<...>
|
|
|
|
Run with the bootstrap root key in env:
|
|
ACDL_BOOTSTRAP_AWS_ACCESS_KEY_ID / ACDL_BOOTSTRAP_AWS_SECRET_ACCESS_KEY
|
|
AWS_DEFAULT_REGION (defaults to us-east-1)
|
|
|
|
The inline policy is read from spike_runner_policy.json (next to this
|
|
file). The account id + region are already substituted in the policy file
|
|
for account 581513795199 + us-east-1; this script does not substitute
|
|
further (the policy file is spike-specific).
|
|
|
|
Idempotent: re-running this script against an already-bootstrapped account
|
|
exits 0 without duplicating resources. The IAM user is guarded by a
|
|
get_user probe (skips creation if it exists), the inline policy is
|
|
re-PUT on every run (PutUserPolicy overwrites in place), and the initial
|
|
access key is created only when no active key exists (list_access_keys
|
|
filters on Status=Active; if one is present the script returns without
|
|
creating another, directing the operator to rotate_spike_key.sh).
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
import boto3
|
|
|
|
|
|
REGION = os.environ.get("AWS_DEFAULT_REGION", "us-east-1")
|
|
USER_NAME = "acdl-spike-runner"
|
|
POLICY_NAME = "acdl-spike-runner-policy"
|
|
POLICY_FILE = os.path.join(os.path.dirname(__file__), "spike_runner_policy.json")
|
|
|
|
|
|
def main():
|
|
session = boto3.Session(
|
|
aws_access_key_id=os.environ["ACDL_BOOTSTRAP_AWS_ACCESS_KEY_ID"],
|
|
aws_secret_access_key=os.environ["ACDL_BOOTSTRAP_AWS_SECRET_ACCESS_KEY"],
|
|
region_name=REGION,
|
|
)
|
|
iam = session.client("iam")
|
|
|
|
# --- IAM user (idempotent) ---
|
|
try:
|
|
iam.get_user(UserName=USER_NAME)
|
|
print(f"iam: user {USER_NAME} already exists")
|
|
except iam.exceptions.NoSuchEntityException:
|
|
iam.create_user(UserName=USER_NAME)
|
|
print(f"iam: created user {USER_NAME}")
|
|
|
|
# --- Inline policy (idempotent: put_user_policy overwrites) ---
|
|
with open(POLICY_FILE, "r") as fh:
|
|
policy_doc = fh.read()
|
|
iam.put_user_policy(
|
|
UserName=USER_NAME,
|
|
PolicyName=POLICY_NAME,
|
|
PolicyDocument=policy_doc,
|
|
)
|
|
print(f"iam: inline policy {POLICY_NAME} attached to {USER_NAME}")
|
|
|
|
# --- Initial access key (create only if no active key exists) ---
|
|
keys = iam.list_access_keys(UserName=USER_NAME).get("AccessKeyMetadata", [])
|
|
active = [k for k in keys if k["Status"] == "Active"]
|
|
if active:
|
|
print(f"iam: {USER_NAME} already has {len(active)} active key(s); not creating a new one")
|
|
print(" (use scripts/rotate_spike_key.sh to rotate)")
|
|
return
|
|
new_key = iam.create_access_key(UserName=USER_NAME)["AccessKey"]
|
|
print("ACDL_AWS_ACCESS_KEY_ID=" + new_key["AccessKeyId"])
|
|
print("ACDL_AWS_SECRET_ACCESS_KEY=" + new_key["SecretAccessKey"])
|
|
print(f"iam: created initial access key {new_key['AccessKeyId']} for {USER_NAME}", file=sys.stderr)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |