"""Create the Nova 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): NOVA_AWS_ACCESS_KEY_ID=<...> NOVA_AWS_SECRET_ACCESS_KEY=<...> Run with the bootstrap root key in env: NOVA_BOOTSTRAP_AWS_ACCESS_KEY_ID / NOVA_BOOTSTRAP_AWS_SECRET_ACCESS_KEY (falls back to NOVA_AWS_ACCESS_KEY_ID / NOVA_AWS_SECRET_ACCESS_KEY when the provided key is a root principal). 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 = "nova-spike-runner" POLICY_NAME = "nova-spike-runner-policy" POLICY_FILE = os.path.join(os.path.dirname(__file__), "spike_runner_policy.json") def main(): key_id = os.environ.get("NOVA_BOOTSTRAP_AWS_ACCESS_KEY_ID") or os.environ.get("NOVA_AWS_ACCESS_KEY_ID") secret = os.environ.get("NOVA_BOOTSTRAP_AWS_SECRET_ACCESS_KEY") or os.environ.get("NOVA_AWS_SECRET_ACCESS_KEY") if not key_id or not secret: sys.exit("FAIL: set NOVA_BOOTSTRAP_AWS_ACCESS_KEY_ID + NOVA_BOOTSTRAP_AWS_SECRET_ACCESS_KEY (root key)") session = boto3.Session( aws_access_key_id=key_id, aws_secret_access_key=secret, 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("NOVA_AWS_ACCESS_KEY_ID=" + new_key["AccessKeyId"]) print("NOVA_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()