From 3512214d14932f58cb18c4958bb88a15dc0d8dca Mon Sep 17 00:00:00 2001 From: Adam Moussa Date: Wed, 5 Aug 2026 12:56:24 -0400 Subject: [PATCH 1/2] fix(iam): allow s3:* on afi artifact bucket for provider reads First HCP apply failed on s3:GetBucketAcl after CreateBucket; scope remains the single artifact bucket ARN. --- .../terraform-substrate.template.yaml | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/lib/terraform-substrate/terraform-substrate.template.yaml b/lib/terraform-substrate/terraform-substrate.template.yaml index ff90bf3..5df4dde 100644 --- a/lib/terraform-substrate/terraform-substrate.template.yaml +++ b/lib/terraform-substrate/terraform-substrate.template.yaml @@ -498,26 +498,14 @@ Resources: Resource: "*" # Artifact bucket for HCP plan/apply split: zip bytes travel in the # plan via aws_s3_object content_base64 (local archive_file paths - # from the plan worker are not on the apply worker). + # from the plan worker are not on the apply worker). Action set is + # s3:* on this bucket only — the AWS provider reads many GetBucket* + # attributes (e.g. GetBucketAcl) after CreateBucket; enumerating + # them lags provider upgrades (PLAT-56 first-apply miss). - Sid: LambdaArtifactsBucket Effect: Allow Action: - - s3:CreateBucket - - s3:DeleteBucket - - s3:GetBucketLocation - - s3:GetBucketPolicy - - s3:PutBucketPolicy - - s3:DeleteBucketPolicy - - s3:GetBucketVersioning - - s3:PutBucketVersioning - - s3:GetBucketPublicAccessBlock - - s3:PutBucketPublicAccessBlock - - s3:GetBucketTagging - - s3:PutBucketTagging - - s3:ListBucket - - s3:GetObject - - s3:PutObject - - s3:DeleteObject + - s3:* Resource: - !Sub "arn:aws:s3:::afi-backup-monitor-artifacts-${AWS::AccountId}" - !Sub "arn:aws:s3:::afi-backup-monitor-artifacts-${AWS::AccountId}/*" From f4292832fe2ada6f10dfdbbd669ced520f121d94 Mon Sep 17 00:00:00 2001 From: Adam Moussa Date: Wed, 5 Aug 2026 12:57:23 -0400 Subject: [PATCH 2/2] fix(iam): add plan-role refresh reads for afi terraform state ViewOnlyAccess omits iam:GetRole and events:DescribeRule; without a scoped refresh policy, HCP plans fail after the first partial apply. --- .../terraform-substrate.template.yaml | 64 +++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/lib/terraform-substrate/terraform-substrate.template.yaml b/lib/terraform-substrate/terraform-substrate.template.yaml index 5df4dde..7d92126 100644 --- a/lib/terraform-substrate/terraform-substrate.template.yaml +++ b/lib/terraform-substrate/terraform-substrate.template.yaml @@ -377,10 +377,12 @@ Resources: # # First HCP Terraform workload. Trust subs are exact StringEquals on # organization/project/workspace/run_phase — never StringLike, never a - # wildcarded run_phase. Plan role: ViewOnlyAccess only (never ReadOnlyAccess, - # which grants secretsmanager:GetSecretValue). Apply role: attaches the - # shared guardrail plus stack-scoped Lambda / layer / EventBridge / Logs. - # Prod-only (IsProdAccount): this template also deploys to seahaven-dev. + # wildcarded run_phase. Plan role: ViewOnlyAccess (never ReadOnlyAccess, + # which grants secretsmanager:GetSecretValue) PLUS a stack-scoped refresh + # inline policy — ViewOnlyAccess omits iam:GetRole and events:DescribeRule, + # which Terraform needs to refresh state after the first apply. Apply role: + # attaches the shared guardrail plus stack-scoped Lambda / layer / + # EventBridge / Logs / artifact-bucket. Prod-only (IsProdAccount). # --------------------------------------------------------------------------- HcptfAfiBackupMonitorPlanRole: Type: AWS::IAM::Role @@ -400,6 +402,60 @@ Resources: "app.terraform.io:sub": organization:seahaven:project:seahaven-prod:workspace:afi-backup-monitor-prod:run_phase:plan ManagedPolicyArns: - arn:aws:iam::aws:policy/job-function/ViewOnlyAccess + Policies: + - PolicyName: afi-backup-monitor-plan-refresh + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: RefreshIamRoles + Effect: Allow + Action: + - iam:GetRole + - iam:GetRolePolicy + - iam:ListRolePolicies + - iam:ListAttachedRolePolicies + Resource: + - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/afi-*" + - Sid: RefreshManagedPolicies + Effect: Allow + Action: + - iam:GetPolicy + - iam:GetPolicyVersion + Resource: "*" + - Sid: RefreshEventBridge + Effect: Allow + Action: + - events:DescribeRule + - events:ListTargetsByRule + - events:ListTagsForResource + Resource: + - !Sub "arn:aws:events:us-east-1:${AWS::AccountId}:rule/afi-*" + - Sid: RefreshLambda + Effect: Allow + Action: + - lambda:GetFunction + - lambda:GetFunctionConfiguration + - lambda:GetPolicy + - lambda:GetLayerVersion + - lambda:ListVersionsByFunction + - lambda:ListTags + Resource: + - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:afi-*" + - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:layer:afi-shared*" + - Sid: RefreshArtifactsBucket + Effect: Allow + Action: + - s3:Get* + - s3:ListBucket + Resource: + - !Sub "arn:aws:s3:::afi-backup-monitor-artifacts-${AWS::AccountId}" + - !Sub "arn:aws:s3:::afi-backup-monitor-artifacts-${AWS::AccountId}/*" + - Sid: RefreshLogs + Effect: Allow + Action: + - logs:DescribeLogGroups + - logs:ListTagsForResource + Resource: "*" HcptfAfiBackupMonitorApplyRole: Type: AWS::IAM::Role