Skip to content

sec(iac/azure): scope nested access_policy detection to azurerm_key_vault, using an HCL parse rather than a fourth regex #204

Description

@cristim

Split out of LeanerCloud/cloud-commitments-cli#1817 after the nested-block detection produced three rounds of CodeRabbit findings on the same matcher. The resource-form ban that LeanerCloud/cloud-commitments-cli#1621 actually needs is unaffected and ships in LeanerCloud/cloud-commitments-cli#1817.

Background: why this is being separated

LeanerCloud/cloud-commitments-cli#1621 is about resource "azurerm_key_vault_access_policy" grants against an RBAC-enabled vault, which apply cleanly and then do nothing at runtime. LeanerCloud/cloud-commitments-cli#1817 closes that: the two grants are converted to azurerm_role_assignment, and a guard bans the resource form.

A second axis was added as hardening, detecting the nested forms (access_policy { } and dynamic "access_policy" { } inside azurerm_key_vault), which express the same inert grant. That axis has now been through three corrections:

  1. Too narrow. The original matcher saw only the top-level resource form, so a nested block was reported clean. Reproduced.
  2. Too broad. Widening it to catch nested blocks made it a prefix match, so access_policy_enabled = false and an unrelated access_policy = "metadata" both failed CI on valid Terraform. Reproduced: the guard exited 1 and named both lines.
  3. Still too broad. Tightened to require a whole block header, it now matches access_policy { in any resource without checking the enclosing type. A valid non-Key-Vault resource carrying such a block fails CI.

Each fix was correct for the case it addressed, and each surfaced the next. That pattern is the signal to change approach rather than write a fourth regex.

Current state

Zero instances of either nested form exist in the tree (rg 'access_policy[[:space:]]*\{|dynamic[[:space:]]+"access_policy"' over terraform/ and iac/ returns nothing), and zero azurerm_key_vault_access_policy resources remain after LeanerCloud/cloud-commitments-cli#1817. So removing the nested axis loses no protection that is doing work today, while keeping it in LeanerCloud/cloud-commitments-cli#1817 blocks a security fix behind repeated rounds on optional hardening.

What to build

Detection scoped to the enclosing resource type: an access_policy block matters only inside azurerm_key_vault. Anywhere else it belongs to a different provider resource and is none of this guard's business.

Prefer a real HCL parse over a fourth text matcher. hclparse / hclsyntax in Go, or terraform show -json on a plan, gives the enclosing block type directly instead of inferring it from indentation and braces. A text matcher that tracks brace depth to infer scope is exactly the kind of thing that produces round four.

Verification bar

Both directions, and the negatives are where the previous rounds failed:

Must catch: access_policy { } inside azurerm_key_vault; dynamic "access_policy" { } inside azurerm_key_vault; both at arbitrary indentation.

Must ignore: an access_policy block inside any non-Key-Vault resource; access_policy_enabled = false; access_policy = "metadata"; a prose mention of the resource type inside a comment; .tf.json handling must stay fail-closed (exit 2) rather than silently clean.

Assert the reported file and line, not only the exit code. A guard that exits 1 with a blank or wrong message passes an exit-code-only suite, which the LeanerCloud/cloud-commitments-cli#1817 suite was found doing before it was extended.

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