Skip to content

fix(kms): use regime-aware local for kms_protection_level and propagate to downstream stages - #233

Open
AloysJehwin wants to merge 2 commits into
google:mainfrom
AloysJehwin:fix/kms-protection-level-local
Open

AloysJehwin wants to merge 2 commits into
google:mainfrom
AloysJehwin:fix/kms-protection-level-local

Conversation

@AloysJehwin

Copy link
Copy Markdown
Contributor

Summary

Fixes #231.

kms.tf referenced var.kms_protection_level directly instead of the already-computed local.kms_protection_level. That local uses coalesce to apply a regime-aware default (SOFTWARE for FEDRAMP_MODERATE, HSM for all other regimes). The bypass meant:

  • On a vanilla deployment the version_template.protection_level would be an empty string unless the operator explicitly set the variable.
  • On FedRAMP High / IL5, pressing Enter at the four interactive prompts silently downgraded every CMEK key from HSM to an empty-string protection level.

Changes

  • 0-bootstrap/kms.tf (line 18): var.kms_protection_levellocal.kms_protection_level
  • 0-bootstrap/outputs.tf (line 111, 168): add kms_protection_level = local.kms_protection_level to local.tfvars so stages 1/2/3 receive it via .auto.tfvars.json; also fix standalone output to use the local
  • 1-resman/variables.tf, 2-networking-a-fedramp/variables.tf, 3-security/variables.tf: add default = null and # tfdoc:variable:source 0-bootstrap to kms_protection_level declarations
  • 0-bootstrap/terraform.tfvars.sample: document the variable with an explanatory comment

Test plan

  • terraform validate passes in 0-bootstrap, 1-resman, 2-networking-a-fedramp, 3-security
  • FEDRAMP_MODERATE deployment: confirm local.kms_protection_level resolves to SOFTWARE
  • FEDRAMP_HIGH deployment: confirm local.kms_protection_level resolves to HSM
  • Stages 1/2/3 receive kms_protection_level from .auto.tfvars.json without prompting

Signed-off-by: Aloys Jehwin aloysjehwin@gmail.com

…te to downstream stages

kms.tf used var.kms_protection_level directly, ignoring the coalesce-based
local that computes a regime-aware default (SOFTWARE for FedRAMP Moderate,
HSM otherwise). An operator following the deployment guide saw four interactive
prompts for an undocumented variable; pressing Enter silently downgraded KMS
protection from HSM to empty string on FedRAMP High deployments.

- kms.tf: use local.kms_protection_level instead of var.kms_protection_level
- outputs.tf: add kms_protection_level to tfvars so stages 1/2/3 inherit it
- stages 1/2/3 variables.tf: add default = null and tfdoc:variable:source
- terraform.tfvars.sample: document the variable with a comment

Fixes google#231

Signed-off-by: Aloys Jehwin <aloysjehwin@gmail.com>
@Calvin-Cheng1
Calvin-Cheng1 self-requested a review September 11, 2026 18:00
version_template = {
algorithm = "GOOGLE_SYMMETRIC_ENCRYPTION"
protection_level = var.kms_protection_level
protection_level = local.kms_protection_level

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we even use local.protection_level anywhere, would suggest removing this altogether if that is the case

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consolidate, can you move the local declaration of local.kms_protection_level from main.tf into kms.tf? I think this will make it easier to track

Per review, the local is declared beside the keys that consume it
rather than in main.tf, so the regime-aware default and the
version_template that uses it are read together.

No behavior change: the coalesce expression is unchanged and locals
are stage-scoped, so outputs.tf still resolves it.

Claude-Session: https://claude.ai/code/session_01CFRv5kvesfnKYgHmNw9Vpf
@AloysJehwin

Copy link
Copy Markdown
Contributor Author

Thanks for the review — pushed acf8520.

Moved the local into kms.tf as suggested. It now sits directly above the version_template that consumes it, so the regime-aware default and its use are read together. Locals are stage-scoped, so outputs.tf still resolves it; no behavior change.

On removing local.protection_level — I want to check we're reading the same line, because I don't think there is one. kms.tf has:

locals {
  version_template = {
    algorithm        = "GOOGLE_SYMMETRIC_ENCRYPTION"
    protection_level = local.kms_protection_level
  }
}

protection_level there is an attribute key inside the version_template map, not a local. There is no local.protection_level anywhere in the repo:

$ grep -rn 'local\.protection_level' --include='*.tf' .
(no matches)

The map it belongs to is consumed by both keys in this stage:

fast/stages-aw/0-bootstrap/kms.tf:32:      version_template = local.version_template
fast/stages-aw/0-bootstrap/kms.tf:75:      version_template = local.version_template

protection_level is also the attribute name the modules/kms key schema expects, so dropping it would remove the protection level from both the log-sink and the tenant keys and silently fall back to the provider default — which is the opposite of what #231 is about.

Happy to remove something if I've misread which line you meant — could you point me at it? Otherwise I think this one is a no-op and the branch is ready for another look.

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

Labels

None yet

Projects

None yet

2 participants