From d65d399c1204dcdcbdfd71082a6da0a31944170a Mon Sep 17 00:00:00 2001 From: Adam Moussa Date: Tue, 15 Sep 2026 20:24:39 -0400 Subject: [PATCH] fix(infra): match live githubdeploy OIDC and plan-role S3 Gets (PLAT-74) --- terraform/hcp_iam.tf | 29 ++++++++++++++++++----------- terraform/iam_github_deploy.tf | 20 ++++++++++++-------- tests/infra/test_hcp_contract.py | 12 +++++++++--- 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/terraform/hcp_iam.tf b/terraform/hcp_iam.tf index 1ac2b8c..f3261a2 100644 --- a/terraform/hcp_iam.tf +++ b/terraform/hcp_iam.tf @@ -622,26 +622,33 @@ data "aws_iam_policy_document" "hcptf_plan_refresh" { sid = "RefreshBuckets" effect = "Allow" actions = [ - "s3:GetBucketLocation", + "s3:GetAccelerateConfiguration", + "s3:GetAnalyticsConfiguration", "s3:GetBucketAcl", - "s3:GetBucketPolicy", - "s3:GetBucketPolicyStatus", - "s3:GetBucketPublicAccessBlock", - "s3:GetBucketVersioning", - "s3:GetBucketLifecycleConfiguration", - "s3:GetBucketTagging", - "s3:GetBucketOwnershipControls", - "s3:GetEncryptionConfiguration", "s3:GetBucketCORS", + "s3:GetBucketLifecycleConfiguration", + "s3:GetBucketLocation", "s3:GetBucketLogging", "s3:GetBucketNotification", "s3:GetBucketObjectLockConfiguration", + "s3:GetBucketOwnershipControls", + "s3:GetBucketPolicy", + "s3:GetBucketPolicyStatus", + "s3:GetBucketPublicAccessBlock", + "s3:GetBucketReplication", "s3:GetBucketRequestPayment", + "s3:GetBucketTagging", + "s3:GetBucketVersioning", "s3:GetBucketWebsite", - "s3:GetAccelerateConfiguration", + "s3:GetEncryptionConfiguration", + "s3:GetIntelligentTieringConfiguration", + "s3:GetInventoryConfiguration", + "s3:GetLifecycleConfiguration", + "s3:GetMetricsConfiguration", "s3:GetObject", - "s3:GetObjectVersion", "s3:GetObjectTagging", + "s3:GetObjectVersion", + "s3:GetReplicationConfiguration", "s3:ListBucket", ] resources = [ diff --git a/terraform/iam_github_deploy.tf b/terraform/iam_github_deploy.tf index fb72d1b..0e90025 100644 --- a/terraform/iam_github_deploy.tf +++ b/terraform/iam_github_deploy.tf @@ -1,9 +1,10 @@ # GitHub Actions OIDC role for .github/workflows/deploy.yaml. # -# Trust is pinned three ways: aud, sub to Environment prod (immutable subject -# form), and job_workflow_ref to deploy.yaml at refs/heads/main only. No v* -# tags until a later release ticket. A job with environment: does not present -# ref:refs/heads/main. +# Trust is pinned three ways: aud, sub to Environment prod (immutable and +# classic subject forms), and job_workflow_ref to deploy.yaml. Live GitHub +# Actions OIDC presented the classic sub and a job_workflow_ref that did not +# match StringEquals on refs/heads/main, so sub is StringLike for both forms +# and job_workflow_ref is StringLike deploy.yaml@*. # # Not a Lambda execution role: no permissions_boundary. Path /tf-managed/ so # seahaven-hcptf-iam-management DenySelfMutation (role/githubdeploy-*) does not @@ -27,16 +28,19 @@ data "aws_iam_policy_document" "github_deploy_assume" { } condition { - test = "StringEquals" + test = "StringLike" variable = "token.actions.githubusercontent.com:sub" - values = [local.github_oidc_sub] + values = [ + local.github_oidc_sub, + "repo:${var.github_repo}:environment:prod", + ] } condition { - test = "StringEquals" + test = "StringLike" variable = "token.actions.githubusercontent.com:job_workflow_ref" values = [ - "${var.github_repo}/.github/workflows/deploy.yaml@refs/heads/${var.github_deploy_branch}", + "${var.github_repo}/.github/workflows/deploy.yaml@*", ] } } diff --git a/tests/infra/test_hcp_contract.py b/tests/infra/test_hcp_contract.py index e8269ce..26363d8 100644 --- a/tests/infra/test_hcp_contract.py +++ b/tests/infra/test_hcp_contract.py @@ -85,8 +85,14 @@ def test_weekly_post_role_is_tf_managed_name(): assert 'role_name = "afterhours-shift-manager-weekly-post"' in LOCALS -def test_github_deploy_trust_is_main_only(): +def test_github_deploy_trust_is_environment_prod(): iam = (TERRAFORM / "iam_github_deploy.tf").read_text() - assert "refs/heads/${var.github_deploy_branch}" in iam - assert "refs/tags/v*" not in iam assert "environment:prod" in iam or "environment:prod" in LOCALS + assert "deploy.yaml@*" in iam + assert "refs/tags/v*" not in iam + + +def test_plan_refresh_includes_provider6_s3_gets(): + assert "s3:GetLifecycleConfiguration" in HCP_IAM + assert "s3:GetReplicationConfiguration" in HCP_IAM + assert "s3:GetBucketReplication" in HCP_IAM