| name | ipa-security |
| description | Provision or update centralized security infrastructure (IAM roles) for an IPA project. Use when the user says 'security', 'set up security', 'IAM roles', or invokes /ipa-security. |
| model | opus |
/ipa-security — Provision Security Infrastructure
This skill provisions or updates centralized security infrastructure for an IPA project: IAM execution roles. It supports three configuration paths:
- Existing Role ARN — Builder provides pre-provisioned role ARNs (no IAM creation)
- Managed Policy ARN — IPA creates Builder and CodeBuild roles with a chosen managed policy
- Innovation Builder Stack — Deploys IPA's pre-authored security stack (permissions boundary + 47-service policy + Builder/CodeBuild/SageMaker/EC2 roles)
All paths produce one CloudFormation stack: {namespace}-{env}-security (IAM/roles). The resulting identifiers are written to .env for consumption by downstream IPA skills (/ipa-compose, /ipa-deploy, /ipa-codepipeline).
Initial security provisioning is triggered automatically on first /ipa-compose run. Direct invocation of /ipa-security is reserved for reviewing or updating an existing configuration.
AWS credential resolution: All aws CLI commands must be prefixed with source .env 2>/dev/null; to load credentials into the environment. Do NOT pass --profile or --region flags explicitly.
Invocation modes
| Arguments | Caller | Obligation when done |
|---|
mode=init path={name} | /ipa-compose Step 1.5 | Do not end your turn. Report one line and continue /ipa-compose Step 2 in the same turn. |
| (none) | The builder, directly | Report the full summary and next steps, then stop. |
mode=init carries the path the caller already chose, so skip Step 2 (Path Selection) and go straight to that path's input step. Everything else in this skill behaves identically in both modes.
Resolve path by name, never by letter:
path= | Step to run |
|---|
existing-roles (or legacy A) | Step 3b — Existing Role ARN Input |
managed-policy (or legacy B) | Step 3a — Managed Policy Input |
innovation-builder (or legacy C) | Step 3c — Innovation Builder Stack |
The legacy letters come from /ipa-compose's option ordering (A Existing, B Managed, C Innovation), which is not this skill's step ordering (3a Managed, 3b Existing, 3c Innovation). Letter-matching path=A to "Step 3a" prompts for a managed policy when the builder asked to supply their own role ARNs — two of the three letters are crossed, and the only one that happens to line up is C. Match on the name.
Why the obligation is stated twice (here and at Step 8.4): a skill is loaded into the calling turn, not called and returned from, so nothing resumes compose except this skill continuing to work. Two measured runs ended at exactly this boundary, each leaving a security stack, no Makefiles, and a success report.
Variable Schema
The skill manages these variables in the .env file's # IPA Security Configuration block:
| Variable | Set By | Condition | Description |
|---|
APP_BUILDER_ROLE_ARN | Stack output or builder input | Always | Builder execution role ARN |
APP_CODEBUILD_ROLE_ARN | Stack output or builder input | Always (managed policy) / Optional (existing role) | CodeBuild execution role ARN |
APP_KMS_KEY_ARN | (removed — no longer prompted) | (legacy) | KMS key ARN — skill always uses SSE-S3 (AES-256); this variable is not written to .env |
Derived at runtime (not stored in .env):
- Security stack name:
{APP_NAMESPACE}-{APP_ENV}-security (convention)
- Managed policy: read from CloudFormation stack parameters via
describe-stacks
.env File Format
Security variables use standard KEY=VALUE format — no quotes, no export, no spaces around =. They are written as a group under the # IPA Security Configuration header comment, AFTER the existing # IPA Project Configuration block written by /ipa-init.
Validation Rules
Validate every builder-provided value before proceeding. If validation fails, display the error message and re-prompt.
| Input | Pattern | Error Message |
|---|
| Managed policy (short name) | /^[A-Za-z][A-Za-z0-9+=,.@_-]{0,127}$/ | "Invalid policy name — must be a valid IAM policy name" |
| Managed policy (AWS ARN) | /^arn:aws:iam::aws:policy\/[A-Za-z0-9+=,.@_\/-]+$/ | "Invalid AWS managed policy ARN format" |
| Managed policy (custom ARN) | /^arn:aws:iam::\d{12}:policy\/[A-Za-z0-9+=,.@_\/-]+$/ | "Invalid customer managed policy ARN format" |
| Existing role ARN | /^arn:aws:iam::\d{12}:role\/[A-Za-z0-9+=,.@_\/-]+$/ | "Invalid role ARN — expected format: arn:aws:iam::{account}:role/{name}" |
| KMS key ARN | /^arn:aws:kms:[a-z0-9-]+:\d{12}:key\/[a-f0-9-]+$/ | "Invalid KMS key ARN format" |
Accept all three managed policy formats:
- Short name:
MyCustomPolicy → resolve to arn:aws:iam::aws:policy/MyCustomPolicy
- AWS-managed ARN:
arn:aws:iam::aws:policy/ReadOnlyAccess → use as-is
- Customer-managed ARN:
arn:aws:iam::123456789012:policy/CustomPolicy → use as-is
Step 1: Pre-Flight Checks
Before any prompting, verify prerequisites and determine execution flow.
1.1 Verify .env Prerequisites
Read .env at the project root and check for these variables (written by /ipa-init):
APP_NAMESPACE
APP_ENV
AWS_ACCOUNT_ID
AWS_REGION
AWS_PROFILE
If any are missing: STOP with: "Cannot proceed — .env is missing required IPA variables. Run /ipa-init first to configure project defaults."
1.2 Detect Existing Security Configuration
Check if .env contains APP_BUILDER_ROLE_ARN:
- If present → route to the Update Flow (see "Re-Run / Update Flow" section).
- If absent → continue to step 1.3.
1.3 Check CloudFormation Stack Status
Compute the stack name: {APP_NAMESPACE}-{APP_ENV}-security
Run:
source .env 2>/dev/null; aws cloudformation describe-stacks \
--stack-name {APP_NAMESPACE}-{APP_ENV}-security \
--query 'Stacks[0].StackStatus' \
--output text
- Stack does not exist → continue with First-Time Flow (Step 2).
- Stack exists and NOT
ROLLBACK_COMPLETE → route to Update Flow.
- Stack in
ROLLBACK_COMPLETE → route to ROLLBACK_COMPLETE Recovery (see "Error Handling" section).
Step 2: Path Selection (First-Time Flow)
Use AskUserQuestion with 1 question:
Security configuration (header: "IAM Roles", multiSelect: false)
-
Question: "How should IPA configure IAM execution roles?"
-
Options:
- "Innovation Builder Stack (Recommended)" — "Deploy IPA's pre-authored security stack (permissions boundary + 47-service policy + builder/CodeBuild/SageMaker/EC2 roles)"
- "Managed policy" — "IPA creates Builder and CodeBuild roles; you provide the policy name"
- "Existing role ARNs" — "Skip role creation; provide pre-provisioned role ARNs"
-
If the builder selects "Innovation Builder Stack" → proceed to Step 3c: Innovation Builder Stack.
-
If the builder selects "Managed policy" → proceed to Step 3a: Managed Policy Input.
-
If the builder selects "Existing role ARNs" → proceed to Step 3b: Existing Role ARN Input.
Step 3a: Managed Policy Input
- Use AskUserQuestion:
- Question: "Which managed policy should IPA attach to both execution roles?"
- Header: "Policy"
- Options:
- "PowerUserAccess (Recommended)" — "Broad AWS access without IAM administration"
- "ReadOnlyAccess" — "Read-only access across AWS services"
- multiSelect: false
The builder may select a predefined option or use "Other" to type a custom policy name or full ARN (e.g.,
MyCustomPolicy or arn:aws:iam::123456789012:policy/MyPolicy).
- Validate the input against the three accepted formats (see Validation Rules).
- If it's a short name (no
arn: prefix): resolve to arn:aws:iam::aws:policy/{name}.
- Store the resolved ARN as
ManagedPolicyArn for template generation.
- Proceed to Step 5: Confirmation Summary.
Step 3b: Existing Role ARN Input
3b.1 Builder Execution Role (Required)
- Prompt: "Enter the Builder execution role ARN:"
- Validate ARN format (see Validation Rules).
- Verify the role exists:
source .env 2>/dev/null; aws iam get-role \
--role-name {role_name_extracted_from_arn}
- If the role is not found: display "Role not found:
{arn}. Check the ARN and try again." and re-prompt.
3b.2 CodeBuild Execution Role (Optional)
- Prompt: "Enter the CodeBuild execution role ARN, or press Enter to skip (can be provided later via
/ipa-codepipeline):"
- If provided:
- Validate ARN format.
- Verify the role exists (same
aws iam get-role check).
- If not found: display error and re-prompt.
- If skipped (empty input): note that
APP_CODEBUILD_ROLE_ARN will be omitted from .env.
3b.3 Permissions Warning
After role validation, display:
Note: IPA cannot validate that these roles have sufficient permissions for your composed pattern. If deployments fail with permission errors, re-run /ipa-security with a managed policy instead.
- Proceed to Step 5: Confirmation Summary.
Step 3c: Innovation Builder Stack
When the builder selects the Innovation Builder path, gather two inputs:
3c.1 TrustedPrincipalArn
Use AskUserQuestion:
- Question: "Which IAM principal should be trusted to assume the builder role?"
- Header: "Principal"
- Options:
- "Use my current caller (Recommended)" — "Detect from
aws sts get-caller-identity"
- "Paste ARN" — "Provide a specific IAM role, user, or root ARN"
- multiSelect: false
If "Use my current caller":
- Run:
source .env 2>/dev/null; aws sts get-caller-identity --query Arn --output text
- If the ARN is an assumed-role ARN (
arn:aws:sts::{acct}:assumed-role/{role}/{session}):
- Convert to the underlying IAM role:
arn:aws:iam::{acct}:role/{role}
- Display: "Detected caller:
{converted_arn} (converted from assumed-role session)"
- If the ARN is an IAM user (
arn:aws:iam::{acct}:user/{name}) or root (arn:aws:iam::{acct}:root):
- Use as-is.
- Display: "Detected caller:
{arn}"
- If STS call fails: fall back to the "Paste ARN" flow silently.
If "Paste ARN":
- Prompt: "Enter the trusted principal ARN:"
- Validate:
^arn:aws:iam::\d{12}:(role|user)/.+$ or ^arn:aws:iam::\d{12}:root$
- If invalid: display error and re-prompt.
Store the validated ARN as TRUSTED_PRINCIPAL_ARN.
3c.2 RoleExpirationDate
Compute the default: today + 6 months.
- macOS:
date -v+6m +%Y-%m-%d
- Linux:
date -d "+6 months" +%Y-%m-%d
Prompt: "Enter role expiration date (YYYY-MM-DD, default: {computed_default}):"
- If empty/Enter: use the computed default.
- Validate:
^\d{4}-\d{2}-\d{2}$ and must be > today.
- If invalid: display error and re-prompt.
Store as ROLE_EXPIRATION_DATE.
3c.3 Proceed
Proceed to Step 5: Confirmation Summary with path = "Innovation Builder Stack".
Step 5: Confirmation Summary
Display a confirmation table before deployment. Adapt the content based on the chosen path.
Managed Policy Path Example:
┌──────────────────────┬─────────────────────────────────────────────────┬───────────────┐
│ Setting │ Value │ Source │
├──────────────────────┼─────────────────────────────────────────────────┼───────────────┤
│ Path │ Managed Policy │ prompted │
│ Managed Policy │ {builder's policy} │ prompted │
│ Builder Role │ (will be created) │ generated │
│ CodeBuild Role │ (will be created) │ generated │
│ Security Stack │ myproject-dev-security │ computed │
└──────────────────────┴─────────────────────────────────────────────────┴───────────────┘
Existing Role ARN Path Example:
┌──────────────────────┬─────────────────────────────────────────────────┬───────────────┐
│ Setting │ Value │ Source │
├──────────────────────┼─────────────────────────────────────────────────┼───────────────┤
│ Path │ Existing Role ARNs │ prompted │
│ Builder Role ARN │ arn:aws:iam::123456789012:role/my-builder │ prompted │
│ CodeBuild Role ARN │ (skipped — deferred to /ipa-codepipeline) │ skipped │
│ Security Stack │ myproject-dev-security │ computed │
└──────────────────────┴─────────────────────────────────────────────────┴───────────────┘
Innovation Builder Stack Path Example:
┌──────────────────────┬─────────────────────────────────────────────────┬───────────────┐
│ Setting │ Value │ Source │
├──────────────────────┼─────────────────────────────────────────────────┼───────────────┤
│ Path │ Innovation Builder Stack │ prompted │
│ Trusted Principal │ arn:aws:iam::123456789012:role/MySSO │ detected │
│ Role Expiration │ 2026-11-07 │ default+6mo │
│ Builder Role │ (will be created: myproject-dev-builder) │ generated │
│ CodeBuild Role │ (will be created: myproject-dev-codebuild) │ generated │
│ SageMaker Role │ (will be created: myproject-dev-sagemaker) │ generated │
│ EC2 Builder Role │ (will be created: myproject-dev-ec2-builder) │ generated │
│ Security Stack │ myproject-dev-security │ computed │
└──────────────────────┴─────────────────────────────────────────────────┴───────────────┘
Use AskUserQuestion:
-
Question: "Deploy this security configuration?"
-
Header: "Deploy"
-
Options:
- "Yes, deploy" — "Deploy the security stack with the configuration shown above"
- "No, start over" — "Return to path selection and re-enter configuration"
-
multiSelect: false
-
If "Yes, deploy" → proceed to Step 6: Generate and Deploy.
-
If "No, start over" → restart from Step 2.
Step 6: Generate Templates (if needed)
Create the directory if it does not exist:
mkdir -p infra/cfn/generated
6a: Managed Policy Path — Generate infra/cfn/generated/iam.yml
Write infra/cfn/generated/iam.yml (IAM roles only, no log bucket):
AWSTemplateFormatVersion: "2010-09-09"
Description: "IPA Security Stack — IAM execution roles (managed policy path)"
Parameters:
Namespace:
Type: String
Environment:
Type: String
AccountId:
Type: String
ManagedPolicyArn:
Type: String
Resources:
BuilderExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${Namespace}-${Environment}-builder"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
AWS: !Sub "arn:aws:iam::${AccountId}:root"
Action: "sts:AssumeRole"
ManagedPolicyArns:
- !Ref ManagedPolicyArn
CodeBuildExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${Namespace}-${Environment}-codebuild"
AssumeRolePolicyDocument:
Version:
6b: Existing Role ARN Path
No template generated — roles already exist. Skip to Step 7.
6c: Innovation Builder Stack Path
No template generated — uses the existing vendored template at
infra/cfn/security/innovation-builder-security.yml (consumed as-is, never modified).
Step 7: Deploy Security Stack
Deploy one CloudFormation stack: {APP_NAMESPACE}-{APP_ENV}-security.
7.2a Deploy Security Stack — Managed Policy Path
source .env 2>/dev/null; aws cloudformation deploy \
--template-file infra/cfn/generated/iam.yml \
--stack-name {APP_NAMESPACE}-{APP_ENV}-security \
--parameter-overrides \
Namespace={APP_NAMESPACE} \
Environment={APP_ENV} \
AccountId={AWS_ACCOUNT_ID} \
ManagedPolicyArn={resolved_arn} \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset
7.2b Deploy Security Stack — Existing Role ARN Path
No security stack deployment needed (roles already exist). Skip to Step 8.
7.2c Deploy Security Stack — Innovation Builder Stack Path
source .env 2>/dev/null; aws cloudformation deploy \
--template-file infra/cfn/security/innovation-builder-security.yml \
--stack-name {APP_NAMESPACE}-{APP_ENV}-security \
--capabilities CAPABILITY_NAMED_IAM \
--parameter-overrides \
TrustedPrincipalArn={TRUSTED_PRINCIPAL_ARN} \
RoleExpirationDate={ROLE_EXPIRATION_DATE} \
BoundaryPolicyName={APP_NAMESPACE}-{APP_ENV}-InnovationBuilderBoundary \
CodeBuildRoleName={APP_NAMESPACE}-{APP_ENV}-codebuild \
SageMakerRoleName={APP_NAMESPACE}-{APP_ENV}-sagemaker \
EC2BuilderRoleName={APP_NAMESPACE}-{APP_ENV}-ec2-builder \
BuilderRoleName={APP_NAMESPACE}-{APP_ENV}-builder \
--no-fail-on-empty-changeset
7.3 Wait for Deployment
Monitor the deployment. If it fails, proceed to the Error Handling section.
If the deployment succeeds, proceed to Step 8: Write .env.
Step 8: Write .env Security Variables
8.1 Retrieve Stack Outputs
For paths A (Managed Policy) and C (Innovation Builder), read outputs from the security stack:
source .env 2>/dev/null; aws cloudformation describe-stacks \
--stack-name {APP_NAMESPACE}-{APP_ENV}-security \
--query 'Stacks[0].Outputs' \
--output json
Extract:
BuilderRoleArn → APP_BUILDER_ROLE_ARN
CodeBuildRoleArn → APP_CODEBUILD_ROLE_ARN
For path B (Existing Role ARN), the builder provided the values directly.
8.2 Compose .env Security Block
Managed Policy Path (A):
# IPA Security Configuration
# Generated by /ipa-security — local only, do not commit
APP_BUILDER_ROLE_ARN={from stack output BuilderRoleArn}
APP_CODEBUILD_ROLE_ARN={from stack output CodeBuildRoleArn}
Existing Role ARN Path (B):
# IPA Security Configuration
# Generated by /ipa-security — local only, do not commit
APP_BUILDER_ROLE_ARN={builder-provided ARN}
Include APP_CODEBUILD_ROLE_ARN={builder-provided ARN} only if the builder provided a CodeBuild role ARN (not skipped).
Innovation Builder Stack Path (C):
# IPA Security Configuration
# Generated by /ipa-security — local only, do not commit
APP_BUILDER_ROLE_ARN={from stack output BuilderRoleArn}
APP_CODEBUILD_ROLE_ARN={from stack output CodeBuildRoleArn}
8.3 .env Update Strategy
- Read the existing
.env file.
- Look for the
# IPA Security Configuration header line.
- If the block exists: replace everything from that header through the next blank line (or end of file) with the new security block.
- If the block does not exist: append the security block after the last line of the file (add a blank line separator first).
- Preserve all other content: init variables (
# IPA Project Configuration block), non-IPA variables, comments, and blank lines MUST remain unchanged in their original positions.
8.4 Completion Message
The completion message depends on how this skill was invoked, and the mode=init case is the one that goes wrong. There is no "return" from a skill: /ipa-compose delegated here by loading these instructions into the same turn, so the only way back to its Step 2 is to keep working in that same turn. A completion report that reads as terminal is treated as terminal — measured twice (2026-08-08, 2026-08-18), and both runs ended here having generated none of compose's eight artifacts while reporting success.
If invoked as part of /ipa-compose (mode=init): emit ONE line and nothing else —
Security configured: {APP_NAMESPACE}-{APP_ENV}-security deployed, .env updated.
Then continue immediately with /ipa-compose Step 2 (Stack Discovery) in this same turn. Do NOT display the summary block below, do NOT display next steps, do NOT ask the builder anything, and do NOT end your turn — compose is unfinished, and stopping here leaves the project with a security stack, no Makefiles, and no way to deploy.
If invoked directly, display: "Security infrastructure deployed. .env updated with security variables."
Show a summary of written values:
Written to .env:
APP_BUILDER_ROLE_ARN={value}
APP_CODEBUILD_ROLE_ARN={value}
Stack deployed:
{APP_NAMESPACE}-{APP_ENV}-security (IAM roles)
Then display next steps:
Next steps:
• Run `/ipa-compose` to compose infrastructure and generate Makefiles
• Run `/ipa-security` again to review or update the configuration
Re-Run / Update Flow
This flow runs when pre-flight checks detect existing security configuration (Step 1.2 or 1.3).
U1: Read Current Configuration
- Read from
.env: APP_BUILDER_ROLE_ARN, APP_CODEBUILD_ROLE_ARN (may be absent)
- Compute security stack name:
{APP_NAMESPACE}-{APP_ENV}-security
- Query the stack:
source .env 2>/dev/null; aws cloudformation describe-stacks \
--stack-name {APP_NAMESPACE}-{APP_ENV}-security \
--output json
- Extract from the response:
Stacks[0].StackStatus — verify it's a *_COMPLETE state (not ROLLBACK_COMPLETE)
Stacks[0].Parameters — determine active path:
- If
TrustedPrincipalArn parameter present → Innovation Builder path (C)
- If
ManagedPolicyArn parameter present → Managed Policy path (A)
- Otherwise → Existing Role ARN path (B)
Stacks[0].Outputs — extract role ARNs (for display)
U2: Display Current Configuration
Infrastructure context (optional):
Run:
source .env 2>/dev/null; aws cloudformation list-stacks \
--stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE \
--query "StackSummaries[?starts_with(StackName, '{APP_NAMESPACE}-{APP_ENV}')].{Name:StackName,Status:StackStatus,Updated:LastUpdatedTime}" \
--output table
If successful, display the output prefixed with:
Current Infrastructure ({APP_NAMESPACE}-{APP_ENV}):
{list-stacks output}
If the command fails, skip silently.
Security configuration table:
Display the configuration table using values from .env reads (role ARNs, KMS) and CloudFormation queries (path, managed policy, log bucket, stack name):
Current Security Configuration:
┌──────────────────────┬─────────────────────────────────────────────────┐
│ Setting │ Current Value │
├──────────────────────┼─────────────────────────────────────────────────┤
│ Path │ {from stack resources} │
│ Managed Policy │ {from stack parameter ManagedPolicyArn} │
│ Builder Role ARN │ {from .env APP_BUILDER_ROLE_ARN} │
│ CodeBuild Role ARN │ {from .env APP_CODEBUILD_ROLE_ARN} │
│ Security Stack │ {APP_NAMESPACE}-{APP_ENV}-security (computed) │
└──────────────────────┴─────────────────────────────────────────────────┘
Infer the current path from the stack's describe-stacks response:
- If
TrustedPrincipalArn parameter present → "Innovation Builder Stack"
- If
ManagedPolicyArn parameter present → "Managed Policy"
- Otherwise → "Existing Role ARNs"
Pre-mark the active path in the three-way choice (Step 2) when the builder selects "Yes, update".
U3: Update Prompt
Use AskUserQuestion:
-
Question: "Would you like to update the security configuration?"
-
Header: "Update"
-
Options:
- "Yes, update" — "Modify the security configuration"
- "No, keep current" — "Keep the current configuration as-is"
-
multiSelect: false
-
If "No, keep current": complete with "Security configuration is current. No changes needed."
-
If "Yes, update": proceed to Step 2 (Path Selection) to re-enter the full configuration flow.
U4: Path Switching Warning
If the builder is switching paths:
- Managed → Existing: Use AskUserQuestion:
- Question: "Switching to existing role ARNs will REMOVE the IAM roles currently managed by the security stack. The stack will be updated to contain only the log bucket. Proceed?"
- Header: "Confirm"
- Options:
- "Yes, switch paths" — "Remove managed roles and use existing role ARNs"
- "No, keep current path" — "Stay with managed policy configuration"
- multiSelect: false
- Existing → Managed: "Note: Switching to managed policy will create new IAM roles in the security stack."
U5: No-Change Detection
If CloudFormation returns "No updates are to be performed" during stack update:
- Treat as success.
- Display: "Security stack is up to date. No changes deployed."
- Still refresh
.env from current stack outputs (in case .env was manually edited).
Error Handling
ROLLBACK_COMPLETE Recovery
If the security stack is in ROLLBACK_COMPLETE state:
- Display: "The security stack
{stack_name} is in ROLLBACK_COMPLETE state from a previous failed deployment."
- Use AskUserQuestion:
- Question: "Delete the failed stack and retry?"
- Header: "Recovery"
- Options:
- "Yes, delete and retry" — "Delete the failed stack and create a new one"
- "No, abort" — "Stop here; fix manually via AWS Console or CLI"
- multiSelect: false
- If "Yes, delete and retry":
source .env 2>/dev/null; aws cloudformation delete-stack \
--stack-name {stack_name}
Wait for deletion to complete:
source .env 2>/dev/null; aws cloudformation wait stack-delete-complete \
--stack-name {stack_name}
Then proceed with the First-Time Flow (Step 2).
- If "No, abort": abort with "Aborting. You can manually delete the stack via AWS Console or CLI and re-run
/ipa-security."
Permission Errors
If CloudFormation deployment fails with an IAM permission error:
- Read stack events to identify the failure:
source .env 2>/dev/null; aws cloudformation describe-stack-events \
--stack-name {stack_name} \
--query 'StackEvents[?ResourceStatus==`CREATE_FAILED`].[LogicalResourceId,ResourceStatusReason]' \
--output table
- Display: "Deployment failed due to insufficient IAM permissions: {error}. Your current AWS credentials need
iam:CreateRole and s3:CreateBucket permissions. Options: (a) use the existing-role-ARN path instead, (b) obtain the required permissions and retry."
Bucket Already Exists
If CloudFormation fails with BucketAlreadyExists:
Display: "The log bucket name {bucket_name} already exists in S3 (bucket names are globally unique). This usually means another project or account owns this name. Consider changing your APP_NAMESPACE via /ipa-init to generate a different bucket name."
Invalid Managed Policy
If CloudFormation fails because the managed policy does not exist:
- Read stack events, identify the
AWS::IAM::Role failure.
- Display: "The managed policy
{policy} was not found. Check the policy name/ARN and try again."
- Re-prompt for the managed policy (return to Step 3a).
Missing Prerequisites
If .env does not exist or does not contain IPA init variables:
STOP with: "Cannot proceed — .env is missing or does not contain IPA project configuration. Run /ipa-init first."
Edge Cases
- CloudFormation stack exists but
.env security block is missing: Treat as an update scenario. Read stack outputs and re-populate .env.
.env has security variables but stack doesn't exist: Warn the builder that the stack may have been manually deleted. Offer to re-deploy or clear .env security variables.
- Builder provides the same configuration on re-run: CloudFormation returns "No updates are to be performed" — handle as success per U5.
aws cloudformation list-stacks fails: Skip the infrastructure context display and proceed with the security-specific update flow using targeted describe-stacks calls. The infrastructure listing is informational, not blocking.