Skip to content

chore(iac): low findings from the 2026-09-02 audit: CFN host param, GCP KMS key, dev CORS #324

Description

@cristim

Summary

Three low-severity Terraform and CloudFormation findings from the 2026-09-02 audit, grouped because each is a few-line change in the IaC tree and none is tracked elsewhere. Each item is independently actionable; keep the location and scenario with it if splitting any out.

  • CloudFormation WIF template makes the operator keep the issuer URL and its condition-key host in sync by hand (A13b-014)

    • Location: iac/federation/aws-target/cloudformation/template.yaml:20-28 (OIDCIssuerHost parameter), :265-267 (condition keys) at 3c0f8ac94048a2c36fce5ccddee54e6c4849a5cd
    • What: OIDCIssuerHost is a second free-text parameter whose own description says it must equal OIDCIssuerURL minus https:// and that keeping them in sync is the operator's job. Its two AllowedPatterns constrain shape only. The Terraform sibling derives the host in one line: iac/federation/aws-target/terraform/main.tf:22 (trimsuffix(trimprefix(var.oidc_issuer_url, "https://"), "/")).
    • Failure scenario: the two values disagree by a trailing slash or a tenant-ID typo. IAM never populates <host>:aud / <host>:sub for the incoming token, StringEquals fails, and every AssumeRoleWithWebIdentity is denied. It fails closed, but after the stack reports success, with no diagnostic naming the mismatch.
    • Fix: remove OIDCIssuerHost and derive it as !Select [1, !Split ["https://", !Ref OIDCIssuerURL]] so one input cannot contradict the other. aws-cfn-deploy.sh.tmpl passes the parameter today (see chore(scripts): generate-federation-iac.go iacData has drifted out of sync with the templates it renders #153), so drop it from the parameter overrides in the same change.
  • GCP OIDC signing key is explicitly unprotected where its AWS twin was given create_before_destroy (A13c-024)

    • Location: terraform/modules/compute/gcp/cloud-run/signing-key.tf:24-38 at 3c0f8ac94048a2c36fce5ccddee54e6c4849a5cd
    • What: google_kms_crypto_key.signing sets destroy_scheduled_duration = "86400s" with the comment "tests redeploy often" and an explicit lifecycle { prevent_destroy = false } (Terraform's default, so the line states rather than changes the posture). modules/compute/aws/lambda/signing-key.tf:19-27 carries create_before_destroy = true with a seven-line rationale citing fix(oidc): provision EC P-256 signing keys in Terraform to match ES256 code (follow-up to #882) cloud-commitments-cli#1480: replacing the OIDC signing key destroy-first breaks client-assertion JWT minting. The GCP key has neither mechanism.
    • Failure scenario: a ForceNew change on the key (purpose, version_template.algorithm, or the key ring's location via var.region) in a production project schedules the live signing key for destruction with a one-day window, and every federated target cloud rejects assertions until the new JWKS propagates.
    • Fix: make prevent_destroy and destroy_scheduled_duration module inputs so production gets the protective values and only test environments opt out, and add create_before_destroy = true to match the AWS twin.
  • A live Lambda Function URL hostname is hand-maintained in a tracked tfvars file (A13c-017)

    • Location: terraform/environments/aws/github-dev.tfvars:31-34 at 3c0f8ac94048a2c36fce5ccddee54e6c4849a5cd; terraform/.gitignore:12-16 ignores *.tfvars then re-admits !github-*.tfvars
    • What: the Function URL ID is server-assigned and only known after apply, so lambda_allowed_origins carries it pasted by hand, and the comment three lines above says to update it whenever dev is redeployed. The endpoint is a public URL, not a credential.
    • Failure scenario: a redeploy that reissues the URL silently invalidates the CORS allowlist. The failure surfaces as a browser CORS error, not as a Terraform diff.
    • Fix: supply the origin from the deploy workflow via TF_VAR_lambda_allowed_origins, reading the previous apply's function_url output, instead of committing the host. sec(iac): flip dev/staging/prod to AWS_IAM + enable CloudFront OAC (runtime cut-over for #424) #16 (CloudFront cut-over) would replace this origin with a stable domain and make the item moot; fix here only if sec(iac): flip dev/staging/prod to AWS_IAM + enable CloudFront OAC (runtime cut-over for #424) #16 stays parked.

Found by the 2026-09-02 codebase audit, findings A13b-014, A13c-024, A13c-017, reported by one reviewer and independently confirmed by a second. Full report: docs/audits/codebase-audit-2026-09-02.md.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions