Skip to content

chore(iac/federation): align provider version floors in customer onboarding bundles #55

Open

Description

@cristim

Problem

INF-08 (LeanerCloud/cloud-commitments-cli#1188, PR LeanerCloud/cloud-commitments-cli#1242) aligned the ~> X provider floors across terraform/modules/** and terraform/environments/** to stop module-local lock files from drifting to provider majors no consuming root ever applies.

The same >= X.0 unbounded floor pattern is present in the per-customer federation bundles under iac/federation/**. Each one will resolve to whichever provider major Terraform sees as newest at the customer's terraform init time, which means two customers onboarding a few months apart end up locked to different provider majors with no version policy on our side.

Per iac/federation/*/terraform/main.tf today:

Bundle Provider Current constraint Risk
aws-cross-account hashicorp/aws >= 5.0 resolves to whatever AWS major is current at customer init time
aws-target hashicorp/aws >= 5.0 same
gcp-target hashicorp/google >= 5.0 same for google
gcp-sa-impersonation hashicorp/google >= 5.0 same for google
azure-target hashicorp/azurerm ~> 4.0 already pinned (intentionally on the 4.x line, distinct from the host-side terraform/environments/azure 3.x line)

The azure-target ~> 4.0 is fine and intentional — it's the cross-major split the cudly-reservation-role module's >= 3.0 constraint accommodates (LeanerCloud/cloud-commitments-cli#1242).

The AWS and GCP bundles are the ones that need a deliberate floor.

Why this matters

These bundles are run by customers on their own AWS/GCP accounts as part of CUDly onboarding. Each customer brings their own state and lock files. Today:

  • A customer onboarding now resolves >= 5.0 AWS to whatever 6.x is current; a customer who onboarded 12 months ago landed on 5.x.
  • Our docs, support tickets, and reproduction steps cover whichever provider the doc author had locally at the time of writing.
  • If a future schema break ships in a provider major, customers on the new major silently get a different plan diff for the same .tf source than customers on the old major.
  • Our regression-test stories (e.g. role-parity ARM/TF parity guard, federation smoke tests) cover one provider major at a time.

This is the same drift class INF-08 fixed inside terraform/; we just didn't extend it across the boundary into the customer-facing bundles.

Proposal

Pin each AWS and GCP federation bundle to the same major line our internal modules use, so docs and reproduction stay consistent:

  • iac/federation/aws-cross-account/terraform/main.tf: aws = "~> 5.0"
  • iac/federation/aws-target/terraform/main.tf: aws = "~> 5.0"
  • iac/federation/gcp-target/terraform/main.tf: google = "~> 5.0"
  • iac/federation/gcp-sa-impersonation/terraform/main.tf: google = "~> 5.0"
  • Leave azure-target at ~> 4.0 (deliberate cross-major split with the host-side ~> 3.0).

Optionally also align the http, random, and azuread sub-providers in those same files (currently a mix of >= 3.4, >= 3.0, ~> 3.8, ~> 2.0) so customers see consistent supply-chain pins.

No committed lock files exist under iac/federation/** today (customers generate their own), so there is no lock churn to manage on our side. Pure source-file change plus a docs note in the README of each bundle.

Acceptance

  • AWS and GCP federation bundles use ~> 5.0 floors matching the internal modules; azurerm left at ~> 4.0.
  • terraform init -backend=false && terraform validate clean in each of the five bundle directories.
  • README for each bundle mentions the pinned major and how a customer should bump when CUDly migrates the host-side line.

Out of scope

  • Migrating the host-side azurerm line from ~> 3.0 to ~> 4.0 — that's a much bigger lift (schema migration across every azurerm consumer in terraform/).
  • Adding any new permissions to the bundles. Pure version-pin alignment.

Discovered during the adversarial review of LeanerCloud/cloud-commitments-cli#1242.

Findings from the 2026-09-02 codebase audit

Added by an automated audit of 3c0f8ac94048a2c36fce5ccddee54e6c4849a5cd (tip of origin/main). Each item below was reported by one reviewer and independently confirmed by a second that did not write it. Full report: docs/audits/codebase-audit-2026-09-02.md.

A13-024 (low)

The table here should gain a row. All five bundles also constrain hashicorp/http as >= 3.4 against locks that pin 3.5.0, so the azure-target row marked "already pinned" is only pinned on azuread and azurerm; its http line drifts like the rest. That makes this a five-bundle change rather than four. Two small corrections to the risk framing while the change is being scoped: the committed locks are at aws 6.40.0 and google 7.27.0, so the constraint floors are two majors behind for google and one for aws, and the exposure needs a customer who unpacks into a directory that already has a lock, runs terraform init -upgrade, or is handed only the .tf files. Audit finding A13-024.

Activity

  1. cristim commented on Jul 28, 2026

    @cristim
    MemberAuthor

    Reviewed commit: be11bdcb5. Note: origin/main moved to 3e9660d06 during the review; the enumeration below was re-run against 3e9660d06, but re-verify against current main before changing code.

    Verification result from the 2026-07-28 full IaC review. Two reviewers reached opposite conclusions about whether provider version constraints diverge in this repo, so the constraints were enumerated directly against origin/main at 3e9660d06 (git grep -nE 'version = "' origin/main -- '*.tf'). Verdict below, with the full evidence, so a live finding is not dismissed on a wrong negative.

    Verdict: divergence is real, in two of three claimed places

    1. The iac/federation/** unbounded floors are confirmed still live. Exactly as this issue describes:

    File Provider Constraint
    iac/federation/aws-cross-account/terraform/main.tf:6 hashicorp/aws >= 5.0
    iac/federation/aws-cross-account/terraform/main.tf:10 hashicorp/azurerm >= 3.0
    iac/federation/aws-cross-account/terraform/main.tf:14 hashicorp/http >= 3.4
    iac/federation/aws-target/terraform/main.tf:6 hashicorp/aws >= 5.0
    iac/federation/aws-target/terraform/main.tf:10 hashicorp/http >= 3.4
    iac/federation/gcp-target/terraform/main.tf:6 hashicorp/google >= 5.0
    iac/federation/gcp-target/terraform/main.tf:10 hashicorp/http >= 3.4
    iac/federation/gcp-sa-impersonation/terraform/main.tf:6 hashicorp/google >= 5.0
    iac/federation/gcp-sa-impersonation/terraform/main.tf:10 hashicorp/http >= 3.4
    iac/federation/azure-target/terraform/main.tf:6 hashicorp/azuread ~> 3.8
    iac/federation/azure-target/terraform/main.tf:10 hashicorp/azurerm ~> 4.0
    iac/federation/azure-target/terraform/main.tf:14 hashicorp/http >= 3.4

    Note that http >= 3.4 is unbounded in all five bundles, including azure-target, which this issue lists as "already pinned". The optional http alignment mentioned in the Proposal section is therefore the one item that applies to every bundle without exception, and is worth promoting out of "optionally".

    2. The azurerm 3.x vs 4.x split is deliberate and documented, and is NOT a divergence. The other reviewer is correct on this specific point. terraform/modules/iam/azure/cudly-reservation-role/main.tf:5-12 carries an explicit comment:

        azurerm = {
          # Deliberately >= 3.0 (not ~> 3.0): this module is consumed by both
          # terraform/environments/azure/ci-cd-permissions (azurerm ~> 3.0) and
          # iac/federation/azure-target/terraform (azurerm ~> 4.0), so the
          # constraint must intersect with both provider lines.
          source  = "hashicorp/azurerm"
          version = ">= 3.0"
        }

    The consumption is confirmed on both sides (terraform/environments/azure/ci-cd-permissions/reservation_role.tf:20 and iac/federation/azure-target/terraform/main.tf:68-72). Anyone re-raising the azurerm 3/4 split as a defect should be pointed here; it is load-bearing.

    3. A third divergence exists that this issue's scope explicitly excludes. Inside terraform/environments/aws, two roots pin different AWS provider majors:

    • terraform/environments/aws/main.tf:10: aws ~> 5.0 (matching every module under terraform/modules/**)
    • terraform/environments/aws/ci-cd-permissions/main.tf:10: aws ~> 6.0

    The ci-cd-permissions bootstrap root is the one that provisions the deploy identity's IAM, so it applies IAM resources through a provider major that no other root in the repo has been tested against. This is outside this issue's stated scope (iac/federation/**) and outside #12's table, so it is not currently tracked anywhere. It is carried in the grouped chore(terraform/envs) medium/low issue from this review, cross-referencing this one.

    Practical takeaway for this issue

    Nothing here changes the proposal. It confirms the four AWS/GCP bundle pins are still needed, confirms leaving azure-target at ~> 4.0 is right, and suggests promoting the http >= 3.4 alignment from optional to in-scope since it is the only constraint that is unbounded in all five bundles.

    Related

  2. IAmJSD commented on Oct 23, 2026

    @IAmJSD
    Collaborator

    Claiming: working on this

  3. self-assigned this
    on Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions