Skip to content

Commit 9f7fc5f

Browse files
Add team-scoped Terraform backend access to CI team roles (#91)
## Summary Team CI roles (`javabin-ci-team-{team}`) need access to the shared Terraform state bucket and lock table. Without this, `terraform plan` fails with `AccessDeniedException` on DynamoDB lock operations. Access is fully team-scoped: - **S3**: Only `apps/{team}/*` prefix — teams can't read/write other teams' state - **DynamoDB**: `LeadingKeys` condition restricts lock operations to the team's own state paths This maintains end-to-end ABAC isolation: | Layer | Scope | |-------|-------| | S3 state | `apps/{team}/*` only | | DynamoDB locks | Keys matching `*/apps/{team}/*` only | | Resource tags | `aws:ResourceTag/team == team` | | Resource names | Boundary enforces `{team}-*` prefix | ## Test plan - [ ] Merge and apply - [ ] Re-run test app CI — tf-plan should acquire lock and succeed
1 parent 4c53b90 commit 9f7fc5f

1 file changed

Lines changed: 42 additions & 11 deletions

File tree

terraform/platform/iam/main.tf

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -359,18 +359,49 @@ resource "aws_iam_role_policy" "ci_team_allow" {
359359

360360
policy = jsonencode({
361361
Version = "2012-10-17"
362-
Statement = [{
363-
Sid = "AllowWithTeamTagIsolation"
364-
Effect = "Allow"
365-
Action = "*"
366-
Resource = "*"
367-
Condition = {
368-
StringEqualsIfExists = {
369-
"aws:ResourceTag/team" = each.key
370-
"aws:RequestTag/team" = each.key
362+
Statement = [
363+
{
364+
Sid = "AllowWithTeamTagIsolation"
365+
Effect = "Allow"
366+
Action = "*"
367+
Resource = "*"
368+
Condition = {
369+
StringEqualsIfExists = {
370+
"aws:ResourceTag/team" = each.key
371+
"aws:RequestTag/team" = each.key
372+
}
371373
}
372-
}
373-
}]
374+
},
375+
{
376+
Sid = "AllowTerraformBackend"
377+
Effect = "Allow"
378+
Action = [
379+
"s3:GetObject",
380+
"s3:PutObject",
381+
"s3:DeleteObject",
382+
"s3:ListBucket",
383+
]
384+
Resource = [
385+
"arn:aws:s3:::${var.project}-terraform-state-${var.aws_account_id}",
386+
"arn:aws:s3:::${var.project}-terraform-state-${var.aws_account_id}/apps/${each.key}/*",
387+
]
388+
},
389+
{
390+
Sid = "AllowTerraformLocking"
391+
Effect = "Allow"
392+
Action = [
393+
"dynamodb:GetItem",
394+
"dynamodb:PutItem",
395+
"dynamodb:DeleteItem",
396+
]
397+
Resource = "arn:aws:dynamodb:${var.region}:${var.aws_account_id}:table/${var.project}-terraform-app-locks"
398+
Condition = {
399+
"ForAllValues:StringLike" = {
400+
"dynamodb:LeadingKeys" = "${var.project}-terraform-state-${var.aws_account_id}/apps/${each.key}/*"
401+
}
402+
}
403+
},
404+
]
374405
})
375406
}
376407

0 commit comments

Comments
 (0)