Skip to content

feat(iam): add read-only Terraform plan role (#225 step 1 of 2) - #226

Open
lentago-claude-runner[bot] wants to merge 1 commit into
mainfrom
agent/split-terraform-ci-role-step1
Open

lentago-claude-runner[bot] wants to merge 1 commit into
mainfrom
agent/split-terraform-ci-role-step1

Conversation

@lentago-claude-runner

@lentago-claude-runner lentago-claude-runner Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Step 1 of 2 for #225 (split the Terraform CI role). Part of #225. Step 2, which closes the issue, is the stacked draft PR #227.

Why two steps

Both roles are managed by Terraform, and the plan role doesn't exist until an apply creates it. That apply runs under the existing role, which today trusts only repo:lentago/solidago:environment:terraform. If this PR moved the plan job to the new role, its own PR plan would fail to assume a role that doesn't exist yet. If it also moved the apply job off the environment, its merge apply would fail because the trust change isn't live yet. So this PR creates the role but doesn't switch to it, and step 2 switches the jobs and then narrows the trust. The README section "Terraform CI Roles: Plan vs Apply" documents the ordering.

Changes

  • New role solidago-dev-github-actions-terraform-plan (modules/iam)
    • Trust: exactly repo:lentago/solidago:pull_request. GitHub mints this subject for a PR job that has no environment: key.
    • Permissions: AWS-managed ReadOnlyAccess, plus what a plan needs that ReadOnlyAccess lacks. These come from the backend config and from what refresh reads:
      • s3:GetObject on env/dev/terraform.tfstate, and ListBucket.
      • Get/Put/Delete on only env/dev/terraform.tfstate.tflock. The backend uses S3-native locking (use_lockfile = true), so there's no DynamoDB table for this stack.
      • On the tfstate CMK: Decrypt and DescribeKey, plus GenerateDataKey for the SSE-KMS lockfile PUT.
      • secretsmanager:GetSecretValue on solidago-dev-* secrets, plus kms:Decrypt on the main CMK, but only via Secrets Manager (kms:ViaService). ReadOnlyAccess leaves out GetSecretValue. Refreshing aws_secretsmanager_secret_version (modules/secrets) and the axiom_token data source (modules/alb-log-shipper) needs it, and the main key policy hands authorization to IAM through its root statement.
    • A plan never writes state. An apply under this role is denied on its first mutating call.
  • Existing apply role trust widened, not narrowed: ref:refs/heads/main is added next to the transitional environment:terraform subject.
  • terraform.yml: both jobs gain an AWS caller identity step (aws sts get-caller-identity). Role ARNs are unchanged in this step.
  • trivy:ignore:AVD-AWS-0345 stays on the apply role, because s3:* is there by design. Its comment now says Split the Terraform CI role: read-only plan credentials on pull requests, write apply credentials on main (tf-lint AVD-AWS-0345) #225 resolved Hardening backlog from tf-lint's first trivy run (ECR immutability, CI-role least-privilege, SNS encryption) #180 item 2 as a split.
  • New output github_actions_terraform_plan_role_arn.

Expected plan

Adds 4 resources: the role, a customer policy, and 2 attachments (ReadOnlyAccess and the custom policy). There's one in-place update: the trust policy of module.iam.aws_iam_role.github_actions_terraform. Nothing is destroyed. This PR's plan and merge apply still run under the existing role via environment:terraform.

Verification

  • terraform fmt -check and terraform validate pass for modules/iam and environments/dev.
  • Not verified: no live plan or apply was run from the runner. The CI plan on this PR is the first real check.

Notes for the reviewer

  • Any pull_request workflow in this repo with id-token: write (for example claude.yml or claude-review.yml) can assume the plan role. That gives read-only access to the account, including other repos' state objects through ReadOnlyAccess's s3:Get*. That matches the issue's "ReadOnlyAccess-class" target. Today the same callers can already reach the write role by declaring environment: terraform, because that environment has no deployment-branch policy. Step 2 closes that gap.
  • After this merges and the apply goes green, mark the step 2 PR ready and re-run its plan. Its first plan attempt fails until then, which is expected.

🤖 Generated with Claude Code

Add solidago-dev-github-actions-terraform-plan: AWS ReadOnlyAccess plus
state read, the S3-native lockfile (env/dev/terraform.tfstate.tflock),
the tfstate CMK, and this stack's secret values (ReadOnlyAccess omits
GetSecretValue, which refresh of the secret versions needs). Trusted only
for repo:lentago/solidago:pull_request.

Widen the existing (apply) role's trust to ref:refs/heads/main alongside
the transitional environment:terraform sub. terraform.yml still assumes
the existing role from both jobs, so this PR's own plan and its merge
apply are unaffected; step 2 switches the jobs and drops the legacy sub.

Both jobs now log `aws sts get-caller-identity`. AVD-AWS-0345 ignore
stays on the apply role (s3:* by design) and now points at #225.

Refs #225

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Terraform Plan 📖 success

Show Plan
module.ask_pondview.data.archive_file.this: Reading...
module.ask_pondview.data.archive_file.this: Read complete after 0s [id=69a91fae4132e082b4c49a75a5972aca44a52f0c]
module.s3.data.aws_caller_identity.current: Reading...
module.site_pondview.aws_ecr_repository.this: Refreshing state... [id=solidago-dev-pondview]
module.ecr.aws_ecr_repository.this: Refreshing state... [id=solidago-dev-app]
module.vpc.aws_vpc.this: Refreshing state... [id=vpc-028337a40d2094b37]
module.ask_pondview.data.aws_caller_identity.current: Reading...
module.site_lentago.aws_cloudwatch_log_group.this: Refreshing state... [id=/ecs/solidago-dev-lentago]
data.aws_kms_alias.tfstate: Reading...
module.site_pondview.aws_cloudwatch_log_group.this: Refreshing state... [id=/ecs/solidago-dev-pondview]
module.pondview_domain.aws_acm_certificate.this: Refreshing state... [id=arn:aws:acm:us-east-1:365184644049:certificate/a3462f2a-8285-4230-ba6a-9e1b801a0a8b]
module.s3.data.aws_caller_identity.current: Read complete after 0s [id=365184644049]
module.aws_config.data.aws_iam_policy_document.config_assume_role: Reading...
module.aws_config.data.aws_iam_policy_document.config_assume_role: Read complete after 0s [id=607352202]
module.iam.data.aws_iam_policy_document.ecs_task_assume: Reading...
module.iam.data.aws_iam_policy_document.ecs_task_assume: Read complete after 0s [id=1077804475]
module.ask_pondview.aws_cloudwatch_log_group.this: Refreshing state... [id=/aws/lambda/solidago-dev-pondview-ask]
module.ask_pondview.data.aws_caller_identity.current: Read complete after 0s [id=365184644049]
module.iam.data.aws_iam_policy_document.github_actions_terraform: Reading...
module.iam.data.aws_iam_policy_document.github_actions_terraform: Read complete after 0s [id=4030624528]
data.aws_caller_identity.current: Reading...
data.aws_caller_identity.current: Read complete after 0s [id=365184644049]
module.iam.data.aws_iam_policy_document.ecs_task_execution_assume: Reading...
module.iam.data.aws_iam_policy_document.ecs_task_execution_assume: Read complete after 0s [id=1077804475]
module.lentago_domain.aws_route53_zone.this: Refreshing state... [id=Z03243791ZWX6X5GLR27J]
data.aws_kms_alias.tfstate: Read complete after 0s [id=arn:aws:kms:us-east-1:365184644049:alias/solidago-tfstate]
module.alb.data.aws_elb_service_account.this[0]: Reading...
module.alb.data.aws_elb_service_account.this[0]: Read complete after 0s [id=127311923021]
module.ask_pondview.data.aws_iam_policy_document.assume: Reading...
module.ask_pondview.data.aws_iam_policy_document.assume: Read complete after 0s [id=2690255455]
module.lentago_domain.aws_acm_certificate.this: Refreshing state... [id=arn:aws:acm:us-east-1:365184644049:certificate/c3e6833b-36d5-4af1-b1cb-2b54698624da]
module.ask_pondview.data.aws_partition.current: Reading...
module.ask_pondview.data.aws_partition.current: Read complete after 0s [id=aws]
module.grafana_cloud[0].data.aws_iam_policy_document.grafana_assume: Reading...
module.grafana_cloud[0].data.aws_iam_policy_document.grafana_assume: Read complete after 0s [id=3707719201]
module.grafana_cloud[0].data.aws_iam_policy_document.grafana_cloudwatch_read: Reading...
module.pondview_domain.aws_route53_zone.this: Refreshing state... [id=Z09441732084SCRGLVY6S]
module.grafana_cloud[0].data.aws_iam_policy_document.grafana_cloudwatch_read: Read complete after 0s [id=1998560222]
module.essexcrossing_domain.aws_acm_certificate.this: Refreshing state... [id=arn:aws:acm:us-east-1:365184644049:certificate/0f24e5d9-94cd-40ed-a659-652d01aa55f6]
module.alb.data.aws_caller_identity.current[0]: Reading...
module.site_lentago.aws_ecr_repository.this: Refreshing state... [id=solidago-dev-lentago]
module.alb.data.aws_caller_identity.current[0]: Read complete after 0s [id=365184644049]
module.iam.aws_iam_openid_connect_provider.github: Refreshing state... [id=arn:aws:iam::365184644049:oidc-provider/token.actions.githubusercontent.com]
module.vpc.aws_cloudwatch_log_group.flow_logs[0]: Refreshing state... [id=/aws/vpc/flow-logs/solidago-dev]
module.monitoring.aws_sns_topic.alerts: Refreshing state... [id=arn:aws:sns:us-east-1:365184644049:solidago-dev-alerts]
module.elasticache.aws_elasticache_parameter_group.this: Refreshing state... [id=solidago-dev-valkey7]
module.dns.aws_route53_zone.this: Refreshing state... [id=Z0392486888CR1YFANHI]
module.vpc.aws_eip.nat[1]: Refreshing state... [id=eipalloc-0fa92d3746ed273c0]
module.rds.aws_db_parameter_group.this: Refreshing state... [id=solidago-dev-pg16]
module.vpc.aws_eip.nat[0]: Refreshing state... [id=eipalloc-076957392fe4d2748]
module.uvularia_demo_sandbox.aws_sns_topic.alerts: Refreshing state... [id=arn:aws:sns:us-east-1:365184644049:uvularia-demo-alerts]
module.waf.aws_wafv2_web_acl.this: Refreshing state... [id=857f254b-48e9-4fa3-8abf-d3584736e69b]
module.dns.aws_acm_certificate.this: Refreshing state... [id=arn:aws:acm:us-east-1:365184644049:certificate/460041fa-52e7-4240-96ee-d1a4b19ad7bf]
module.vpc.aws_iam_role.flow_logs[0]: Refreshing state... [id=solidago-dev-flow-logs-role]
module.essexcrossing_domain.aws_route53_zone.this: Refreshing state... [id=Z00397045FW0TURVDXX]
module.s3.aws_s3_bucket.this: Refreshing state... [id=solidago-dev-365184644049]
module.aws_config.aws_iam_role.config: Refreshing state... [id=solidago-dev-config]
module.iam.aws_iam_role.ecs_task: Refreshing state... [id=solidago-dev-ecs-task]
module.iam.aws_iam_policy.github_actions_terraform: Refreshing state... [id=arn:aws:iam::365184644049:policy/solidago-dev-github-actions-terraform]
module.iam.aws_iam_role.ecs_task_execution: Refreshing state... [id=solidago-dev-ecs-task-execution]
module.ask_pondview.aws_iam_role.this: Refreshing state... [id=solidago-dev-pondview-ask]
module.ecr.aws_ecr_lifecycle_policy.this: Refreshing state... [id=solidago-dev-app]
module.site_pondview.aws_ecr_lifecycle_policy.this: Refreshing state... [id=solidago-dev-pondview]
module.grafana_cloud[0].aws_iam_role.grafana_cloudwatch: Refreshing state... [id=solidago-dev-grafana-cloudwatch]
module.alb.aws_s3_bucket.access_logs[0]: Refreshing state... [id=solidago-dev-alb-logs-365184644049]
module.site_lentago.aws_ecr_lifecycle_policy.this: Refreshing state... [id=solidago-dev-lentago]
module.iam.data.aws_iam_policy_document.github_actions_terraform_assume: Reading...
module.iam.data.aws_iam_policy_document.github_actions_terraform_assume: Read complete after 0s [id=92722051]
module.iam.data.aws_iam_policy_document.dotgithub_github_actions_terraform_assume: Reading...
module.iam.data.aws_iam_policy_document.drosera_github_actions_terraform_assume: Reading...
module.iam.data.aws_iam_policy_document.drosera_github_actions_terraform_assume: Read complete after 0s [id=1386998129]
module.iam.data.aws_iam_policy_document.dotgithub_github_actions_terraform_assume: Read complete after 0s [id=2655476866]
module.iam.data.aws_iam_policy_document.github_actions_terraform_plan_assume: Reading...
module.iam.data.aws_iam_policy_document.betula_github_actions_terraform_assume: Reading...
module.iam.data.aws_iam_policy_document.github_actions_terraform_plan_assume: Read complete after 0s [id=2856934371]
module.iam.data.aws_iam_policy_document.betula_github_actions_terraform_assume: Read complete after 0s [id=3623219639]
module.iam.data.aws_iam_policy_document.github_actions_assume: Reading...
module.monitoring.data.aws_iam_policy_document.sns_topic_policy: Reading...
module.iam.data.aws_iam_policy_document.github_actions_assume: Read complete after 0s [id=4127365700]
module.monitoring.aws_sns_topic_subscription.email: Refreshing state... [id=arn:aws:sns:us-east-1:365184644049:solidago-dev-alerts:f65ceb8d-192e-475b-b3e7-94a0a2776a04]
module.monitoring.data.aws_iam_policy_document.sns_topic_policy: Read complete after 0s [id=4001684531]
module.uvularia_demo_sandbox.data.aws_iam_policy_document.alerts: Reading...
module.uvularia_demo_sandbox.data.aws_iam_policy_document.alerts: Read complete after 0s [id=2924315531]
module.uvularia_demo_sandbox.aws_sns_topic_subscription.email: Refreshing state... [id=arn:aws:sns:us-east-1:365184644049:uvularia-demo-alerts:c5adbd60-9ef1-412b-bdce-3b7a6788eb4a]
module.uvularia_demo_sandbox.aws_cloudwatch_metric_alarm.ask_errors: Refreshing state... [id=uvularia-demo-ask-errors]
module.lentago_domain.aws_route53_record.spf[0]: Refreshing state... [id=Z03243791ZWX6X5GLR27J_lentago.dev_TXT]
module.lentago_domain.aws_route53_record.acm_validation["www.lentago.dev"]: Refreshing state... [id=Z03243791ZWX6X5GLR27J__23a2f85a7743bc58b729b2e990202d1c.www.lentago.dev._CNAME]
module.lentago_domain.aws_route53_record.acm_validation["lentago.dev"]: Refreshing state... [id=Z03243791ZWX6X5GLR27J__a40c54db428354ad7df84db85e0fff6e.lentago.dev._CNAME]
module.lentago_domain.aws_route53_record.extra["TXT/_dmarc"]: Refreshing state... [id=Z03243791ZWX6X5GLR27J__dmarc.lentago.dev_TXT]
module.lentago_domain.aws_route53_record.extra["CNAME/fm2._domainkey"]: Refreshing state... [id=Z03243791ZWX6X5GLR27J_fm2._domainkey.lentago.dev_CNAME]
module.lentago_domain.aws_route53_record.extra["CNAME/fm1._domainkey"]: Refreshing state... [id=Z03243791ZWX6X5GLR27J_fm1._domainkey.lentago.dev_CNAME]
module.lentago_domain.aws_route53_record.extra["CNAME/fm3._domainkey"]: Refreshing state... [id=Z03243791ZWX6X5GLR27J_fm3._domainkey.lentago.dev_CNAME]
module.lentago_domain.aws_route53_record.extra["TXT/_gh-lentago-o"]: Refreshing state... [id=Z03243791ZWX6X5GLR27J__gh-lentago-o.lentago.dev_TXT]
module.lentago_domain.aws_route53_record.extra["MX/"]: Refreshing state... [id=Z03243791ZWX6X5GLR27J_lentago.dev_MX]
module.lentago_domain.aws_route53_record.extra["TXT/_github-pages-challenge-lentago"]: Refreshing state... [id=Z03243791ZWX6X5GLR27J__github-pages-challenge-lentago.lentago.dev_TXT]
module.pondview_domain.aws_route53_record.acm_validation["www.pondviewlane.com"]: Refreshing state... [id=Z09441732084SCRGLVY6S__de1d030f87a1810407ddc42c33a8662d.www.pondviewlane.com._CNAME]
module.pondview_domain.aws_route53_record.acm_validation["pondviewlane.com"]: Refreshing state... [id=Z09441732084SCRGLVY6S__df734bf9f06598124eff66c878fc73ac.pondviewlane.com._CNAME]
module.pondview_domain.aws_route53_record.extra["TXT/_dmarc"]: Refreshing state... [id=Z09441732084SCRGLVY6S__dmarc.pondviewlane.com_TXT]
module.pondview_domain.aws_route53_record.spf[0]: Refreshing state... [id=Z09441732084SCRGLVY6S_pondviewlane.com_TXT]
module.dns.aws_route53_record.acm_validation["icecreamtofightwith.com"]: Refreshing state... [id=Z0392486888CR1YFANHI__8431acbae2553cbe59da7225f2f6cd3e.icecreamtofightwith.com._CNAME]
module.dns.aws_route53_record.acm_validation["*.icecreamtofightwith.com"]: Refreshing state... [id=Z0392486888CR1YFANHI__8431acbae2553cbe59da7225f2f6cd3e.icecreamtofightwith.com._CNAME]
module.iam.data.aws_iam_policy_document.drosera_github_actions_terraform: Reading...
module.iam.data.aws_iam_policy_document.drosera_github_actions_terraform: Read complete after 0s [id=3854983119]
module.iam.data.aws_iam_policy_document.betula_github_actions_terraform: Reading...
module.iam.data.aws_iam_policy_document.betula_github_actions_terraform: Read complete after 0s [id=2350579211]
module.iam.data.aws_iam_policy_document.dotgithub_github_actions_terraform: Reading...
module.iam.data.aws_iam_policy_document.dotgithub_github_actions_terraform: Read complete after 0s [id=1603859638]
module.vpc.aws_iam_role_policy.flow_logs[0]: Refreshing state... [id=solidago-dev-flow-logs-role:solidago-dev-flow-logs-policy]
module.essexcrossing_domain.aws_route53_record.acm_validation["www.essexcrossingatmontserrat.com"]: Refreshing state... [id=Z00397045FW0TURVDXX__351f8906e202a0b41e5d80f41cad7b14.www.essexcrossingatmontserrat.com._CNAME]
module.essexcrossing_domain.aws_route53_record.acm_validation["essexcrossingatmontserrat.com"]: Refreshing state... [id=Z00397045FW0TURVDXX__d928179571f68ee128d75a6ba2c97bb2.essexcrossingatmontserrat.com._CNAME]
module.essexcrossing_domain.aws_route53_record.spf[0]: Refreshing state... [id=Z00397045FW0TURVDXX_essexcrossingatmontserrat.com_TXT]
module.essexcrossing_domain.aws_route53_record.extra["TXT/_dmarc"]: Refreshing state... [id=Z00397045FW0TURVDXX__dmarc.essexcrossingatmontserrat.com_TXT]
module.ask_pondview.data.aws_iam_policy_document.this: Reading...
module.ask_pondview.data.aws_iam_policy_document.this: Read complete after 0s [id=4136046911]
module.iam.data.aws_iam_policy_document.github_actions: Reading...
module.iam.data.aws_iam_policy_document.github_actions: Read complete after 0s [id=3143127237]
module.iam.aws_iam_role_policy_attachment.ecs_task_execution_base: Refreshing state... [id=solidago-dev-ecs-task-execution-20260708052618546200000002]
module.iam.aws_iam_role.github_actions_terraform: Refreshing state... [id=solidago-dev-github-actions-terraform]
module.iam.aws_iam_role.drosera_github_actions_terraform: Refreshing state... [id=drosera-github-actions-terraform]
module.iam.aws_iam_role.dotgithub_github_actions_terraform: Refreshing state... [id=dotgithub-github-actions-terraform]
module.iam.aws_iam_role.betula_github_actions_terraform: Refreshing state... [id=betula-github-actions-terraform]
module.iam.aws_iam_role.github_actions: Refreshing state... [id=solidago-dev-github-actions]
module.monitoring.aws_sns_topic_policy.alerts: Refreshing state... [id=arn:aws:sns:us-east-1:365184644049:solidago-dev-alerts]
module.uvularia_demo_sandbox.aws_sns_topic_policy.alerts: Refreshing state... [id=arn:aws:sns:us-east-1:365184644049:uvularia-demo-alerts]
module.aws_config.aws_config_configuration_recorder.this: Refreshing state... [id=solidago-dev]
module.aws_config.aws_iam_role_policy_attachment.config: Refreshing state... [id=solidago-dev-config-20260708052617953900000001]
module.vpc.aws_subnet.app["us-east-1b"]: Refreshing state... [id=subnet-09706eac8bd2b9e2d]
module.vpc.aws_subnet.app["us-east-1a"]: Refreshing state... [id=subnet-0c78c735c132d7ec3]
module.vpc.aws_subnet.data["us-east-1a"]: Refreshing state... [id=subnet-0a9ff21ac3387bcf5]
module.vpc.aws_subnet.data["us-east-1b"]: Refreshing state... [id=subnet-00783e870526d47a8]
module.vpc.aws_internet_gateway.this: Refreshing state... [id=igw-0ac78f562ef0f0335]
module.vpc.aws_flow_log.this[0]: Refreshing state... [id=fl-0666dd976a7b1fb96]
module.vpc.aws_subnet.public["us-east-1b"]: Refreshing state... [id=subnet-0dbf79bffadc4e2b7]
module.vpc.aws_subnet.public["us-east-1a"]: Refreshing state... [id=subnet-0b1053a4e4142c187]
module.s3.aws_s3_bucket_public_access_block.this: Refreshing state... [id=solidago-dev-365184644049]
module.grafana_cloud[0].aws_iam_role_policy.grafana_cloudwatch_read: Refreshing state... [id=solidago-dev-grafana-cloudwatch:solidago-dev-grafana-cloudwatch-readonly]
module.s3.aws_s3_bucket_versioning.this: Refreshing state... [id=solidago-dev-365184644049]
module.s3.data.aws_iam_policy_document.service_access[0]: Reading...
module.s3.data.aws_iam_policy_document.service_access[0]: Read complete after 0s [id=1792976025]
module.lentago_domain.aws_acm_certificate_validation.this: Refreshing state... [id=0001-01-01 00:00:00 +0000 UTC]
module.iam.aws_iam_policy.drosera_github_actions_terraform: Refreshing state... [id=arn:aws:iam::365184644049:policy/drosera-github-actions-terraform]
module.iam.aws_iam_policy.betula_github_actions_terraform: Refreshing state... [id=arn:aws:iam::365184644049:policy/betula-github-actions-terraform]
module.iam.aws_iam_policy.dotgithub_github_actions_terraform: Refreshing state... [id=arn:aws:iam::365184644049:policy/dotgithub-github-actions-terraform]
module.pondview_domain.aws_acm_certificate_validation.this: Refreshing state... [id=2026-07-17 23:39:40.126 +0000 UTC]
module.alb.aws_s3_bucket_public_access_block.access_logs[0]: Refreshing state... [id=solidago-dev-alb-logs-365184644049]
module.alb.aws_s3_bucket_server_side_encryption_configuration.access_logs[0]: Refreshing state... [id=solidago-dev-alb-logs-365184644049]
module.alb.data.aws_iam_policy_document.access_logs[0]: Reading...
module.alb.data.aws_iam_policy_document.access_logs[0]: Read complete after 0s [id=2364305310]
module.alb.aws_s3_bucket_lifecycle_configuration.access_logs[0]: Refreshing state... [id=solidago-dev-alb-logs-365184644049]
module.ask_pondview.aws_iam_role_policy.this: Refreshing state... [id=solidago-dev-pondview-ask:solidago-dev-pondview-ask-policy]
module.iam.aws_iam_policy.github_actions: Refreshing state... [id=arn:aws:iam::365184644049:policy/solidago-dev-github-actions]
module.uvularia_demo_sandbox.data.aws_iam_policy_document.deploy_assume: Reading...
module.uvularia_demo_sandbox.data.aws_iam_policy_document.deploy_assume: Read complete after 0s [id=1463582940]
module.dns.aws_acm_certificate_validation.this: Refreshing state... [id=0001-01-01 00:00:00 +0000 UTC]
module.budgets.aws_budgets_budget.monthly: Refreshing state... [id=365184644049:solidago-dev-monthly]
module.iam.aws_iam_role_policy_attachment.github_actions_terraform: Refreshing state... [id=solidago-dev-github-actions-terraform-arn:aws:iam::365184644049:policy/solidago-dev-github-actions-terraform]
module.uvularia_demo_sandbox.aws_budgets_budget.this: Refreshing state... [id=365184644049:uvularia-demo]
module.essexcrossing_domain.aws_acm_certificate_validation.this: Refreshing state... [id=0001-01-01 00:00:00 +0000 UTC]
module.s3.aws_s3_bucket_policy.this[0]: Refreshing state... [id=solidago-dev-365184644049]
module.uvularia_demo_sandbox.data.aws_iam_policy_document.deploy: Reading...
module.uvularia_demo_sandbox.data.aws_iam_policy_document.deploy: Read complete after 0s [id=1555112859]
module.vpc.aws_route_table.public: Refreshing state... [id=rtb-0e289ee8e0deb2a8d]
module.alb.aws_s3_bucket_policy.access_logs[0]: Refreshing state... [id=solidago-dev-alb-logs-365184644049]
module.vpc.aws_nat_gateway.this[0]: Refreshing state... [id=nat-06f5048a97e59fc7d]
module.kms.aws_kms_key.this: Refreshing state... [id=b4764881-ac85-41ba-bfe4-17d884cf3804]
module.vpc.aws_nat_gateway.this[1]: Refreshing state... [id=nat-0d22d977012b815bd]
module.iam.aws_iam_role_policy_attachment.drosera_github_actions_terraform: Refreshing state... [id=drosera-github-actions-terraform-20261030024846884000000001]
module.iam.aws_iam_role_policy_attachment.betula_github_actions_terraform: Refreshing state... [id=betula-github-actions-terraform-20261006191546738400000001]
module.ask_pondview.aws_lambda_function.this: Refreshing state... [id=solidago-dev-pondview-ask]
module.security_groups.aws_security_group.redis: Refreshing state... [id=sg-06aaa4caabb0e5762]
module.security_groups.aws_security_group.alb: Refreshing state... [id=sg-00ff2bf4261293eb1]
module.security_groups.aws_security_group.rds: Refreshing state... [id=sg-0f58816430670752a]
module.security_groups.aws_security_group.app: Refreshing state... [id=sg-08b2eacdac5390f2d]
module.site_pondview.aws_lb_target_group.this: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:365184644049:targetgroup/solidago-dev-pondview-tg/7a4f72beb14f9851]
module.alb.aws_lb_target_group.app: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:365184644049:targetgroup/solidago-dev-app-tg/13adb34fe2cf989a]
module.site_lentago.aws_lb_target_group.this: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:365184644049:targetgroup/solidago-dev-lentago-tg/652fbe7a9a6e780e]
module.iam.aws_iam_role_policy_attachment.dotgithub_github_actions_terraform: Refreshing state... [id=dotgithub-github-actions-terraform-20260817202544225700000001]
module.aws_config.aws_config_delivery_channel.this: Refreshing state... [id=solidago-dev]
module.aws_config.data.aws_iam_policy_document.config_delivery: Reading...
module.aws_config.data.aws_iam_policy_document.config_delivery: Read complete after 0s [id=3210156384]
module.uvularia_demo_sandbox.aws_iam_policy.deploy: Refreshing state... [id=arn:aws:iam::365184644049:policy/uvularia-demo-ask-deploy]
module.uvularia_demo_sandbox.data.aws_iam_policy_document.boundary: Reading...
module.uvularia_demo_sandbox.data.aws_iam_policy_document.boundary: Read complete after 0s [id=1979083849]
module.iam.aws_iam_role_policy_attachment.github_actions: Refreshing state... [id=solidago-dev-github-actions-20260708052619383400000003]
module.vpc.aws_route_table_association.public[1]: Refreshing state... [id=rtbassoc-0ed8c8ba18ecd66d9]
module.vpc.aws_route_table_association.public[0]: Refreshing state... [id=rtbassoc-0c47c31c7746dba10]
module.vpc.aws_route_table.private[1]: Refreshing state... [id=rtb-0226d2695e29d76b2]
module.vpc.aws_route_table.private[0]: Refreshing state... [id=rtb-03d5c286ef99edb16]
module.kms.aws_kms_alias.this: Refreshing state... [id=alias/solidago-dev-main]
module.security_groups.aws_vpc_security_group_ingress_rule.alb_http: Refreshing state... [id=sgr-028c6c9fb181e6cbd]
module.security_groups.aws_vpc_security_group_ingress_rule.alb_https: Refreshing state... [id=sgr-0dc931625e06dc6d9]
module.security_groups.aws_vpc_security_group_egress_rule.app_to_internet: Refreshing state... [id=sgr-0e95aaa65a1d6e344]
module.security_groups.aws_vpc_security_group_ingress_rule.app_from_alb: Refreshing state... [id=sgr-002649bdf6c784791]
module.security_groups.aws_vpc_security_group_ingress_rule.redis_from_app: Refreshing state... [id=sgr-04dc1336773a5bfa6]
module.security_groups.aws_vpc_security_group_egress_rule.app_to_rds: Refreshing state... [id=sgr-0412095bfc29dd6da]
module.security_groups.aws_vpc_security_group_ingress_rule.rds_from_app: Refreshing state... [id=sgr-040cc9b5e63b27d67]
module.security_groups.aws_vpc_security_group_egress_rule.alb_to_app: Refreshing state... [id=sgr-0610440030447ee78]
module.security_groups.aws_vpc_security_group_egress_rule.app_to_redis: Refreshing state... [id=sgr-03a7fa95dd5007165]
module.aws_config.aws_config_configuration_recorder_status.this: Refreshing state... [id=solidago-dev]
module.aws_config.aws_iam_role_policy.config_delivery: Refreshing state... [id=solidago-dev-config:solidago-dev-config-delivery]
module.elasticache.aws_elasticache_subnet_group.this: Refreshing state... [id=solidago-dev-valkey]
module.rds.aws_db_subnet_group.this: Refreshing state... [id=solidago-dev-db-subnet-group]
module.ask_pondview.aws_lambda_function_url.this: Refreshing state... [id=solidago-dev-pondview-ask]
module.ask_pondview.aws_lambda_permission.url_invoke_function: Refreshing state... [id=AllowPublicInvokeFunction]
module.ask_pondview.aws_lambda_permission.url: Refreshing state... [id=AllowPublicInvokeFunctionUrl]
module.uvularia_demo_sandbox.aws_iam_policy.boundary: Refreshing state... [id=arn:aws:iam::365184644049:policy/uvularia-demo-boundary]
module.vpc.aws_route_table_association.data[1]: Refreshing state... [id=rtbassoc-0586a50a906e8ca41]
module.vpc.aws_route_table_association.data[0]: Refreshing state... [id=rtbassoc-045c87f29d339d7e2]
module.vpc.aws_route_table_association.app[1]: Refreshing state... [id=rtbassoc-0234a8817df4bc5a1]
module.vpc.aws_route_table_association.app[0]: Refreshing state... [id=rtbassoc-034e4d6a8a1f1311f]
module.aws_config.aws_config_config_rule.rules["s3-bucket-encryption"]: Refreshing state... [id=solidago-dev-s3-bucket-encryption]
module.aws_config.aws_config_config_rule.rules["restricted-ssh"]: Refreshing state... [id=solidago-dev-restricted-ssh]
module.aws_config.aws_config_config_rule.rules["rds-storage-encrypted"]: Refreshing state... [id=solidago-dev-rds-storage-encrypted]
module.aws_config.aws_config_config_rule.rules["cloudtrail-enabled"]: Refreshing state... [id=solidago-dev-cloudtrail-enabled]
module.iam.data.aws_iam_policy_document.github_actions_terraform_plan: Reading...
module.iam.data.aws_iam_policy_document.github_actions_terraform_plan: Read complete after 0s [id=1170271143]
module.s3.aws_s3_bucket_server_side_encryption_configuration.this: Refreshing state... [id=solidago-dev-365184644049]
module.secrets.aws_secretsmanager_secret.db_credentials: Refreshing state... [id=arn:aws:secretsmanager:us-east-1:365184644049:secret:solidago-dev/db-credentials-zEytXN]
module.secrets.aws_secretsmanager_secret.axiom_alb_ingest[0]: Refreshing state... [id=arn:aws:secretsmanager:us-east-1:365184644049:secret:solidago-dev-axiom-alb-ingest-header-gjzPWv]
module.secrets.aws_secretsmanager_secret.axiom_ingest[0]: Refreshing state... [id=arn:aws:secretsmanager:us-east-1:365184644049:secret:solidago-dev-axiom-ingest-header-lQa6gp]
module.cloudtrail.aws_cloudtrail.this: Refreshing state... [id=arn:aws:cloudtrail:us-east-1:365184644049:trail/solidago-dev-trail]
module.alb.aws_lb.this: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:365184644049:loadbalancer/app/solidago-dev-alb/9cd2662c6b66898b]
module.uvularia_demo_sandbox.aws_iam_role.deploy: Refreshing state... [id=uvularia-demo-ask-deploy]
module.elasticache.aws_elasticache_replication_group.this: Refreshing state... [id=solidago-dev-valkey]
module.rds.aws_db_instance.this: Refreshing state... [id=db-4YCV45V5NEN2JIWBFOT2O7KI7A]
module.s3.aws_s3_bucket_lifecycle_configuration.this: Refreshing state... [id=solidago-dev-365184644049]
module.secrets.aws_secretsmanager_secret_version.axiom_ingest[0]: Refreshing state... [id=arn:aws:secretsmanager:us-east-1:365184644049:secret:solidago-dev-axiom-ingest-header-lQa6gp|terraform-20260708052640912700000009]
module.secrets.aws_secretsmanager_secret_version.axiom_alb_ingest[0]: Refreshing state... [id=arn:aws:secretsmanager:us-east-1:365184644049:secret:solidago-dev-axiom-alb-ingest-header-gjzPWv|terraform-20260710001725800300000002]
module.secrets.aws_secretsmanager_secret_version.db_credentials: Refreshing state... [id=arn:aws:secretsmanager:us-east-1:365184644049:secret:solidago-dev/db-credentials-zEytXN|terraform-20260708052640849000000008]
module.uvularia_demo_sandbox.aws_iam_role_policy_attachment.deploy: Refreshing state... [id=uvularia-demo-ask-deploy-20261003234103222400000001]
module.iam.data.aws_iam_policy_document.ecs_task_custom: Reading...
module.iam.data.aws_iam_policy_document.ecs_task_execution_custom: Reading...
module.iam.data.aws_iam_policy_document.ecs_task_custom: Read complete after 0s [id=2852278449]
module.iam.data.aws_iam_policy_document.ecs_task_execution_custom: Read complete after 0s [id=1581943769]
module.site_lentago.aws_ecs_task_definition.this: Refreshing state... [id=solidago-dev-lentago]
module.site_pondview.aws_ecs_task_definition.this: Refreshing state... [id=solidago-dev-pondview]
module.iam.aws_iam_policy.ecs_task_custom: Refreshing state... [id=arn:aws:iam::365184644049:policy/solidago-dev-ecs-task-app]
module.iam.aws_iam_policy.ecs_task_execution_custom: Refreshing state... [id=arn:aws:iam::365184644049:policy/solidago-dev-ecs-exec-secrets]
module.alb.aws_lb_listener.http_redirect: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:365184644049:listener/app/solidago-dev-alb/9cd2662c6b66898b/1797f50831668be4]
module.alb.aws_lb_listener.https: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:365184644049:listener/app/solidago-dev-alb/9cd2662c6b66898b/72236e541fb59760]
module.iam.aws_iam_role_policy_attachment.ecs_task_execution_custom: Refreshing state... [id=solidago-dev-ecs-task-execution-2026070805264202850000000b]
module.monitoring.aws_cloudwatch_metric_alarm.rds_free_storage: Refreshing state... [id=solidago-dev-rds-storage-low]
module.monitoring.aws_cloudwatch_metric_alarm.rds_cpu: Refreshing state... [id=solidago-dev-rds-cpu-high]
module.monitoring.aws_cloudwatch_metric_alarm.alb_target_response_time: Refreshing state... [id=solidago-dev-alb-response-slow]
module.monitoring.aws_cloudwatch_metric_alarm.alb_5xx: Refreshing state... [id=solidago-dev-alb-5xx-high]
module.waf.aws_wafv2_web_acl_association.alb: Refreshing state... [id=arn:aws:wafv2:us-east-1:365184644049:regional/webacl/solidago-dev-waf/857f254b-48e9-4fa3-8abf-d3584736e69b,arn:aws:elasticloadbalancing:us-east-1:365184644049:loadbalancer/app/solidago-dev-alb/9cd2662c6b66898b]
module.pondview_domain.aws_route53_record.www: Refreshing state... [id=Z09441732084SCRGLVY6S_www.pondviewlane.com_A]
module.pondview_domain.aws_route53_record.apex: Refreshing state... [id=Z09441732084SCRGLVY6S_pondviewlane.com_A]
module.dns.aws_route53_record.alb_alias[0]: Refreshing state... [id=Z0392486888CR1YFANHI_icecreamtofightwith.com_A]
module.essexcrossing_domain.aws_route53_record.apex: Refreshing state... [id=Z00397045FW0TURVDXX_essexcrossingatmontserrat.com_A]
module.essexcrossing_domain.aws_route53_record.www: Refreshing state... [id=Z00397045FW0TURVDXX_www.essexcrossingatmontserrat.com_A]
module.lentago_domain.aws_route53_record.www: Refreshing state... [id=Z03243791ZWX6X5GLR27J_www.lentago.dev_A]
module.lentago_domain.aws_route53_record.apex: Refreshing state... [id=Z03243791ZWX6X5GLR27J_lentago.dev_A]
module.iam.aws_iam_role_policy_attachment.ecs_task_custom: Refreshing state... [id=solidago-dev-ecs-task-2026070805264193470000000a]
module.alb_log_shipper[0].data.aws_caller_identity.current: Reading...
module.alb_log_shipper[0].data.aws_iam_policy_document.assume: Reading...
module.alb_log_shipper[0].data.aws_iam_policy_document.assume: Read complete after 0s [id=2690255455]
module.alb_log_shipper[0].data.aws_partition.current: Reading...
module.alb_log_shipper[0].data.aws_partition.current: Read complete after 0s [id=aws]
module.alb_log_shipper[0].data.external.build: Reading...
module.alb_log_shipper[0].data.aws_caller_identity.current: Read complete after 0s [id=365184644049]
module.alb_log_shipper[0].data.aws_secretsmanager_secret_version.axiom_token: Reading...
module.alb_log_shipper[0].aws_iam_role.this: Refreshing state... [id=solidago-dev-alb-log-shipper]
module.alb_log_shipper[0].aws_cloudwatch_log_group.this: Refreshing state... [id=/aws/lambda/solidago-dev-alb-log-shipper]
module.monitoring.aws_cloudwatch_metric_alarm.elasticache_cpu: Refreshing state... [id=solidago-dev-cache-cpu-high]
module.alb_log_shipper[0].data.aws_secretsmanager_secret_version.axiom_token: Read complete after 0s [id=arn:aws:secretsmanager:us-east-1:365184644049:secret:solidago-dev-axiom-alb-ingest-header-gjzPWv|AWSCURRENT]
module.monitoring.aws_cloudwatch_metric_alarm.elasticache_memory: Refreshing state... [id=solidago-dev-cache-memory-high]
module.essexcrossing_domain.aws_lb_listener_rule.this: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:365184644049:listener-rule/app/solidago-dev-alb/9cd2662c6b66898b/72236e541fb59760/542be173ea794e06]
module.essexcrossing_domain.aws_lb_listener_certificate.this: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:365184644049:listener/app/solidago-dev-alb/9cd2662c6b66898b/72236e541fb59760_arn:aws:acm:us-east-1:365184644049:certificate/0f24e5d9-94cd-40ed-a659-652d01aa55f6]
module.lentago_domain.aws_lb_listener_certificate.this: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:365184644049:listener/app/solidago-dev-alb/9cd2662c6b66898b/72236e541fb59760_arn:aws:acm:us-east-1:365184644049:certificate/c3e6833b-36d5-4af1-b1cb-2b54698624da]
module.lentago_domain.aws_lb_listener_rule.this: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:365184644049:listener-rule/app/solidago-dev-alb/9cd2662c6b66898b/72236e541fb59760/cb56fb134a3bc933]
module.pondview_domain.aws_lb_listener_rule.this: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:365184644049:listener-rule/app/solidago-dev-alb/9cd2662c6b66898b/72236e541fb59760/989081a6cd382926]
module.pondview_domain.aws_lb_listener_certificate.this: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:365184644049:listener/app/solidago-dev-alb/9cd2662c6b66898b/72236e541fb59760_arn:aws:acm:us-east-1:365184644049:certificate/a3462f2a-8285-4230-ba6a-9e1b801a0a8b]
module.site_lentago.aws_lb_listener_rule.this: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:365184644049:listener-rule/app/solidago-dev-alb/9cd2662c6b66898b/72236e541fb59760/8c802f37b313a8a4]
module.site_pondview.aws_lb_listener_rule.this: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:365184644049:listener-rule/app/solidago-dev-alb/9cd2662c6b66898b/72236e541fb59760/1e25cbe152b1f504]
module.alb_log_shipper[0].data.aws_iam_policy_document.this: Reading...
module.alb_log_shipper[0].data.aws_iam_policy_document.this: Read complete after 0s [id=215127393]
module.alb_log_shipper[0].aws_iam_role_policy.this: Refreshing state... [id=solidago-dev-alb-log-shipper:solidago-dev-alb-log-shipper-policy]
module.ecs.aws_ecs_cluster.this: Refreshing state... [id=arn:aws:ecs:us-east-1:365184644049:cluster/solidago-dev-cluster]
module.ecs.aws_cloudwatch_log_group.app: Refreshing state... [id=/ecs/solidago-dev-app]
module.site_pondview.aws_ecs_service.this: Refreshing state... [id=arn:aws:ecs:us-east-1:365184644049:service/solidago-dev-cluster/solidago-dev-pondview]
module.site_lentago.aws_ecs_service.this: Refreshing state... [id=arn:aws:ecs:us-east-1:365184644049:service/solidago-dev-cluster/solidago-dev-lentago]
module.ecs.aws_ecs_task_definition.app: Refreshing state... [id=solidago-dev-app]
module.alb_log_shipper[0].data.external.build: Read complete after 0s [id=-]
module.alb_log_shipper[0].data.archive_file.this: Reading...
module.alb_log_shipper[0].data.archive_file.this: Read complete after 0s [id=c32fb511c1daeaa8a744e06bfc2fca99750baa46]
module.alb_log_shipper[0].aws_lambda_function.this: Refreshing state... [id=solidago-dev-alb-log-shipper]
module.ecs.aws_ecs_service.app: Refreshing state... [id=arn:aws:ecs:us-east-1:365184644049:service/solidago-dev-cluster/solidago-dev-app]
module.dashboard.aws_cloudwatch_dashboard.this: Refreshing state... [id=solidago-dev]
module.ecs_autoscaling.aws_appautoscaling_target.ecs: Refreshing state... [id=service/solidago-dev-cluster/solidago-dev-app]
module.monitoring.aws_cloudwatch_metric_alarm.ecs_cpu: Refreshing state... [id=solidago-dev-ecs-cpu-high]
module.monitoring.aws_cloudwatch_metric_alarm.ecs_memory: Refreshing state... [id=solidago-dev-ecs-memory-high]
module.alb_log_shipper[0].aws_lambda_permission.allow_s3: Refreshing state... [id=AllowInvokeFromAlbLogsBucket]
module.alb_log_shipper[0].aws_s3_bucket_notification.this: Refreshing state... [id=solidago-dev-alb-logs-365184644049]
module.ecs_autoscaling.aws_appautoscaling_policy.memory: Refreshing state... [id=solidago-dev-memory-scaling]
module.ecs_autoscaling.aws_appautoscaling_policy.cpu: Refreshing state... [id=solidago-dev-cpu-scaling]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create
  ~ update in-place

Terraform will perform the following actions:

  # module.iam.aws_iam_policy.github_actions_terraform_plan will be created
  + resource "aws_iam_policy" "github_actions_terraform_plan" {
      + arn              = (known after apply)
      + attachment_count = (known after apply)
      + id               = (known after apply)
      + name             = "solidago-dev-github-actions-terraform-plan"
      + name_prefix      = (known after apply)
      + path             = "/"
      + policy           = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = "s3:GetObject"
                      + Effect   = "Allow"
                      + Resource = "arn:aws:s3:::solidago-tfstate-365184644049/env/dev/terraform.tfstate"
                      + Sid      = "TerraformStateRead"
                    },
                  + {
                      + Action   = "s3:ListBucket"
                      + Effect   = "Allow"
                      + Resource = "arn:aws:s3:::solidago-tfstate-365184644049"
                      + Sid      = "TerraformStateList"
                    },
                  + {
                      + Action   = [
                          + "s3:PutObject",
                          + "s3:GetObject",
                          + "s3:DeleteObject",
                        ]
                      + Effect   = "Allow"
                      + Resource = "arn:aws:s3:::solidago-tfstate-365184644049/env/dev/terraform.tfstate.tflock"
                      + Sid      = "TerraformStateLock"
                    },
                  + {
                      + Action   = [
                          + "kms:GenerateDataKey",
                          + "kms:DescribeKey",
                          + "kms:Decrypt",
                        ]
                      + Effect   = "Allow"
                      + Resource = "arn:aws:kms:us-east-1:365184644049:key/96af2db4-4dc9-4a89-9343-b2f84af0e6f7"
                      + Sid      = "TerraformStateKMS"
                    },
                  + {
                      + Action   = "secretsmanager:GetSecretValue"
                      + Effect   = "Allow"
                      + Resource = "arn:aws:secretsmanager:us-east-1:365184644049:secret:solidago-dev-*"
                      + Sid      = "StackSecretValues"
                    },
                  + {
                      + Action    = "kms:Decrypt"
                      + Condition = {
                          + StringEquals = {
                              + "kms:ViaService" = "secretsmanager.us-east-1.amazonaws.com"
                            }
                        }
                      + Effect    = "Allow"
                      + Resource  = "arn:aws:kms:us-east-1:365184644049:key/b4764881-ac85-41ba-bfe4-17d884cf3804"
                      + Sid       = "StackSecretDecrypt"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + policy_id        = (known after apply)
      + tags             = {
          + "Name" = "solidago-dev-github-actions-terraform-plan"
        }
      + tags_all         = {
          + "Environment" = "dev"
          + "ManagedBy"   = "terraform"
          + "Name"        = "solidago-dev-github-actions-terraform-plan"
          + "Project"     = "solidago"
        }
    }

  # module.iam.aws_iam_role.github_actions_terraform will be updated in-place
  ~ resource "aws_iam_role" "github_actions_terraform" {
      ~ assume_role_policy    = jsonencode(
          ~ {
              ~ Statement = [
                  ~ {
                      ~ Condition = {
                          ~ StringEquals = {
                              ~ "token.actions.githubusercontent.com:sub" = "repo:lentago/solidago:environment:terraform" -> [
                                  + "repo:lentago/solidago:ref:refs/heads/main",
                                  + "repo:lentago/solidago:environment:terraform",
                                ]
                                # (1 unchanged attribute hidden)
                            }
                        }
                        # (3 unchanged attributes hidden)
                    },
                ]
                # (1 unchanged attribute hidden)
            }
        )
        id                    = "solidago-dev-github-actions-terraform"
        name                  = "solidago-dev-github-actions-terraform"
        tags                  = {
            "Name" = "solidago-dev-github-actions-terraform"
        }
        # (11 unchanged attributes hidden)
    }

  # module.iam.aws_iam_role.github_actions_terraform_plan will be created
  + resource "aws_iam_role" "github_actions_terraform_plan" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRoleWithWebIdentity"
                      + Condition = {
                          + StringEquals = {
                              + "token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
                              + "token.actions.githubusercontent.com:sub" = "repo:lentago/solidago:pull_request"
                            }
                        }
                      + Effect    = "Allow"
                      + Principal = {
                          + Federated = "arn:aws:iam::365184644049:oidc-provider/token.actions.githubusercontent.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "solidago-dev-github-actions-terraform-plan"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + tags                  = {
          + "Name" = "solidago-dev-github-actions-terraform-plan"
        }
      + tags_all              = {
          + "Environment" = "dev"
          + "ManagedBy"   = "terraform"
          + "Name"        = "solidago-dev-github-actions-terraform-plan"
          + "Project"     = "solidago"
        }
      + unique_id             = (known after apply)

      + inline_policy (known after apply)
    }

  # module.iam.aws_iam_role_policy_attachment.github_actions_terraform_plan will be created
  + resource "aws_iam_role_policy_attachment" "github_actions_terraform_plan" {
      + id         = (known after apply)
      + policy_arn = (known after apply)
      + role       = "solidago-dev-github-actions-terraform-plan"
    }

  # module.iam.aws_iam_role_policy_attachment.github_actions_terraform_plan_readonly will be created
  + resource "aws_iam_role_policy_attachment" "github_actions_terraform_plan_readonly" {
      + id         = (known after apply)
      + policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
      + role       = "solidago-dev-github-actions-terraform-plan"
    }

Plan: 4 to add, 1 to change, 0 to destroy.

Changes to Outputs:
  + github_actions_terraform_plan_role_arn         = (known after apply)

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: tfplan

To perform exactly these actions, run the following command to apply:
    terraform apply "tfplan"

Pushed by: @lentago-claude-runner[bot], Action: pull_request

@github-actions

Copy link
Copy Markdown
Contributor

Review (haiku, claude-review.yml)

  1. major: modules/iam/main.tf:437, apply role trust. The write role now also trusts repo:lentago/solidago:ref:refs/heads/main, with no environment: gate. That subject is minted for any job that runs on the default branch, including issue_comment and issues events. The file's own comment at lines 237–240 says so. .github/workflows/claude.yml runs the Claude responder on issue_comment and issues with id-token: write and no environment: key. Its agent steps share the job, so a prompt-injected responder could in principle mint that token and call AssumeRoleWithWebIdentity on the apply role. The PR body says the terraform environment already has no branch or reviewer protection, so the baseline was already open to PR-declared jobs. This change adds the default-branch-context path, which the README presents as "push and workflow_dispatch on main". Verify the subject claim with a test token. Before merge, add reviewer or deployment-branch protection to the terraform environment, or confirm that the responder job cannot run AWS steps.

  2. major: modules/iam/main.tf:557 and :616, plan role. Its trust is the pull_request subject, which every same-repo PR-triggered job receives. That includes claude.yml, which runs on pull_request with id-token: write. The role also grants secretsmanager:GetSecretValue on all solidago-dev-* secrets, which covers db_credentials and the Axiom ingest token. Combined with ReadOnlyAccess's s3:Get* across buckets, any contributor who can push a branch can read this stack's secret values from a PR workflow. The tfstate object, which the role can read directly, already holds the DB password, so the secret grant is not the only exposure. The README and PR body call the role "read-only" and do not mention secret-value reads from PR runs. Reconsider whether plan refresh needs GetSecretValue, and document the exposure if it stays.

  3. minor: README.md:175. The sentence "The Terraform role's trust policy is scoped to the terraform GitHub environment, so only the terraform.yml workflow can assume it" is wrong once this PR merges. The trust now has two subjects.

  4. minor: README.md:179. The section describes the end state in present tense: "A PR run can never hold write credentials" and the write role is "trusted only for ref:refs/heads/main". In the state this PR merges to, terraform.yml:75 still runs the plan job with environment: terraform, and the write role still trusts environment:terraform (modules/iam/main.tf:438). Either the wording or the ordering paragraph should make the current state explicit.

  5. minor: README.md:177. The new "Terraform CI Roles: Plan vs Apply" section narrates substantive feature work but has no Claude co-authorship disclosure at its top, per the README/CHANGELOG convention.

  6. minor: PR body. It has no Closes #225, Fixes #225 or Resolves #225; it says "Part of Split the Terraform CI role: read-only plan credentials on pull requests, write apply credentials on main (tf-lint AVD-AWS-0345) #225" and defers the close to ci(terraform): plan on the read-only role, narrow apply trust to main (#225 step 2 of 2) #227. The intent is deliberate, but the fleet rule requires one of the keywords, so either add it here or record an explicit exemption.

This branch was successfully deployed

1 active deployment
terraform — f9689aac Deployed Oct 30, 2026 by lentago-claude-runner[bot] via Terraform Plan #249
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hardening backlog from tf-lint's first trivy run (ECR immutability, CI-role least-privilege, SNS encryption)

0 participants