IAM user: claude-infisical-bootstrap
Account: 521228113048
Policy name: claude-infisical-bootstrap-read-write (inline)
Last updated: 2026-04-28 UTC
Updated by: #569 (sre-agent investigation → feature-developer-agent patch)
claude-infisical-bootstrap is the sole IAM user available to agent tooling in this account. It is used by:
freescout stack (terraform/freescout/) — plan, apply, state read/write, state lockingdocs/ops/runbooks/freescout.md)LightsailInstanceManagement (Resource: *)Actions: CreateInstances, GetInstances, GetInstance, DeleteInstance, AllocateStaticIp, AttachStaticIp, DetachStaticIp, GetStaticIp, GetStaticIps, PutInstancePublicPorts, GetInstancePortStates, ImportKeyPair, GetKeyPair, GetKeyPairs, DeleteKeyPair, DownloadDefaultKeyPair, GetOperation, GetOperations, GetRegions, GetBlueprints, GetBundles
Why: Terraform's AWS provider requires these to manage the raxx-tickets Lightsail instance, static IP, and firewall rules defined in terraform/freescout/main.tf. GetRegions, GetBlueprints, and GetBundles are required by the Lightsail provider to resolve blueprint and bundle IDs. Resource scoping to specific instance ARNs is not supported by Lightsail IAM (the API enforces name-level checks internally, not ARN-level).
LightsailSnapshotPreApply (Resource: *)Actions: CreateInstanceSnapshot, GetInstanceSnapshots, GetInstanceMetricData
Why: The FreeScout runbook requires a verified snapshot before any destructive terraform apply. CreateInstanceSnapshot takes the pre-apply backup. GetInstanceSnapshots confirms it is in available state before proceeding. GetInstanceMetricData allows the sre-agent to inspect CPU/memory metrics during post-apply verification. Added in #569.
TerraformStateLock (Resource: arn:aws:dynamodb:us-east-1:521228113048:table/raxx-iac-state-locks)Actions: dynamodb:GetItem, dynamodb:PutItem, dynamodb:DeleteItem
Why: Terraform uses a DynamoDB table as a distributed lock when reading or writing state. Without PutItem, terraform plan/apply fails immediately with Error acquiring the state lock. GetItem reads lock state; DeleteItem releases the lock on success or timeout. Scoped to the exact lock table ARN — no other DynamoDB tables are accessible. Added in #569.
TerraformStateBucket (Resource: arn:aws:s3:::raxx-iac-state-prod/*)Actions: s3:GetObject, s3:PutObject, s3:DeleteObject
Why: The freescout terraform backend stores state at s3://raxx-iac-state-prod/freescout/terraform.tfstate (see terraform/freescout/versions.tf). GetObject is required to read current state at plan time. PutObject writes updated state after apply. DeleteObject is required by the AWS provider for state workspace operations. Scoped to raxx-iac-state-prod/* only — no other S3 buckets are accessible. Added in #569.
TerraformStateBucketList (Resource: arn:aws:s3:::raxx-iac-state-prod)Actions: s3:ListBucket
Why: s3:ListBucket must be applied to the bucket ARN (not the /* suffix). Terraform requires it to enumerate state files and detect whether a key exists before attempting a GetObject. Without it, missing-state scenarios return 403 instead of the expected 404, breaking workspace initialization. Scoped to raxx-iac-state-prod only. Added in #569.
raxx-iac-state-prods3:DeleteBucket, s3:CreateBucket, or bucket-policy managementdynamodb:CreateTable, dynamodb:DeleteTable, or table management beyond the three lock operationsiam:* actions (cannot self-modify or create other users)lightsail:DeleteInstanceSnapshot (snapshots are append-only from this user)| Date (UTC) | Change | Issue |
|---|---|---|
| 2026-04-28 | Original policy created — Lightsail instance management only | (initial bootstrap) |
| 2026-04-28 | Added LightsailSnapshotPreApply, TerraformStateLock, TerraformStateBucket, TerraformStateBucketList |
#569 |
After any policy update, confirm all three permission groups via IAM policy simulation:
# DynamoDB state lock
aws iam simulate-principal-policy \
--policy-source-arn "arn:aws:iam::521228113048:user/claude-infisical-bootstrap" \
--action-names "dynamodb:GetItem" "dynamodb:PutItem" "dynamodb:DeleteItem" \
--resource-arns "arn:aws:dynamodb:us-east-1:521228113048:table/raxx-iac-state-locks" \
--query 'EvaluationResults[*].{Action:EvalActionName,Decision:EvalDecision}'
# S3 object operations
aws iam simulate-principal-policy \
--policy-source-arn "arn:aws:iam::521228113048:user/claude-infisical-bootstrap" \
--action-names "s3:GetObject" "s3:PutObject" "s3:DeleteObject" \
--resource-arns "arn:aws:s3:::raxx-iac-state-prod/freescout/terraform.tfstate" \
--query 'EvaluationResults[*].{Action:EvalActionName,Decision:EvalDecision}'
# S3 bucket list
aws iam simulate-principal-policy \
--policy-source-arn "arn:aws:iam::521228113048:user/claude-infisical-bootstrap" \
--action-names "s3:ListBucket" \
--resource-arns "arn:aws:s3:::raxx-iac-state-prod" \
--query 'EvaluationResults[*].{Action:EvalActionName,Decision:EvalDecision}'
# Lightsail snapshot
aws iam simulate-principal-policy \
--policy-source-arn "arn:aws:iam::521228113048:user/claude-infisical-bootstrap" \
--action-names "lightsail:CreateInstanceSnapshot" "lightsail:GetInstanceSnapshots" "lightsail:GetInstanceMetricData" \
--resource-arns "*" \
--query 'EvaluationResults[*].{Action:EvalActionName,Decision:EvalDecision}'
All decisions should be allowed.
To read the live policy JSON:
aws iam get-user-policy \
--user-name claude-infisical-bootstrap \
--policy-name claude-infisical-bootstrap-read-write \
--query 'PolicyDocument'