docs: record DataAction registry invariant for CheckAccess mapping changes - #26
Merged
Artem Kolomeetc (arxhive) merged 3 commits intoAug 21, 2026
Merged
Conversation
…anges Guard composes DataAction strings in getResourceAndAction/getDataActions, but it does not own that namespace. An action string is only authorizable if the resource provider already publishes the matching operation. When it does not, ARM rejects the action in custom role definitions and the built-in Reader and Writer roles enumerate leaf actions, so only wildcard-bearing roles can match. The request is then denied for every principal on a least-privilege role with no customer-side remediation. Document the invariant, the az verification command, the current registered and unregistered action inventory, and the two reasons this is easy to miss in review: unit tests assert the composed string rather than its grantability, and system:-prefixed identities keep standard clusters from reproducing it.
Ryan Zhang (ryanzhang-oss)
approved these changes
Aug 18, 2026
|
are the graphs in the description anywhere in the repo? |
Document the DataAction Id composition path, which the Azure provider README did not previously cover. The README described only the subresource attribute allowlist, so the two subresource mechanisms were easy to conflate. Add a DataAction Mapping section with three mermaid diagrams: how an action is resolved, the review gate for a mapping change, and the split between the DataAction Id and the subresource attribute. Record the registry invariant, the az verification command, and the current registered and unregistered actions. Clarify the existing Subresource Support section so it states that it covers the attribute mechanism only, and cross-link the two. Point CLAUDE.md at the README so the short operational form and the full explanation stay together.
Reader and Writer were both described as leaf-enumerated. That holds for Reader, whose 31 DataActions all end in /read, but not for Writer: 24 of its 35 DataActions are resource wildcards, including Microsoft.ContainerService/managedClusters/pods/*. An Azure RBAC * spans /, so pods/* matches pods/attach/action. An unregistered action is therefore still reachable whenever Writer carries a wildcard over the parent resource. nodes/proxy/action and certificatesigningrequests/nodeclient/action fall under no Reader or Writer entry, so those stay Admin and Cluster Admin only. Record the per-role shape and the per-action reachability, and correct the resolution diagram node that named only Admin and Cluster Admin. Refresh the inventory date after re-running both checks. Measured with az role definition list for the four built-in roles and az provider operation show --namespace Microsoft.ContainerService.
Author
Yes, as of 42e6f03. They are in
The first diagram has since been amended in 8119167: its "wildcard roles match" node named only Admin and Cluster Admin, which chrischangcode's review showed to be wrong because Writer carries |
chrischangcode
approved these changes
Aug 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
getResourceAndActionandgetDataActions. Guard does not own that action namespace.CLAUDE.md.Documentation only. No code changes.
Changes
CLAUDE.md:system:user bypass inauthz/providers/azure/azure.go.az provider operation showcommand to verify each new action.InvalidDataActionOrNotDataAction. Reader is leaf-only, so it never matches. Writer is mixed, so it does match an unregistered action whose parent resource one of its wildcards covers. Only a covering wildcard matches at all.system:identities hide the change on standard clusters.How the facts were verified
Each statement was measured, not assumed:
pods/exec/actionis registeredaz provider operation show --namespace Microsoft.ContainerServicecertificatesigningrequests/nodeclient/actionis absentpods/{attach,portforward,proxy}/actionare absentservices/proxy/actionandnodes/proxy/actionare absentaz role definition createreturnedInvalidDataActionOrNotDataActionaz role definition listfor all four built-in rolesArchitecture Diagrams
How Guard resolves a DataAction today, and where an unregistered action fails:
flowchart TD A[SubjectAccessReview] --> B{User starts with 'system:'?} B -->|Yes| C[NoOpinion. Azure RBAC is skipped.<br/>Standard AKS nodes stop here.] B -->|No| D[getResourceAndAction] D --> E[DataAction string] E --> F{Operation published by the RP?} F -->|Yes| G[Role can grant it.<br/>Allow or deny by assignment.] F -->|No| H["Only a covering wildcard matches.<br/>Writer where it has resource/*,<br/>otherwise Admin and Cluster Admin."] H --> I[Denied for Reader and<br/>for every custom role] I --> J[Customer cannot fix it.<br/>ARM refuses the action<br/>in a custom role.] style C fill:#fff4ce,stroke:#8a6d00,color:#000 style H fill:#ffd6cc,stroke:#a33,color:#000 style I fill:#ffd6cc,stroke:#a33,color:#000 style J fill:#ffb3a7,stroke:#a33,color:#000Review process before and after this change:
flowchart LR subgraph BEFORE["Before"] A1[Change the mapping] --> A2[Add a unit test<br/>for the string] A2 --> A3[Tests pass] A3 --> A4[Merge] A4 --> A5[Denials found<br/>in production] end subgraph AFTER["After"] B1[Change the mapping] --> B2[Add a unit test<br/>for the string] B2 --> B3[NEW: check the RP<br/>operations registry] B3 --> B4{Operation exists?} B4 -->|Yes| B5[Merge] B4 -->|No| B6[Hold. The RP manifest<br/>must ship first.] end style A5 fill:#ffd6cc,stroke:#a33,color:#000 style B3 fill:#d4f5d4,stroke:#2a7,color:#000 style B6 fill:#fff4ce,stroke:#8a6d00,color:#000Infrastructure Changes
None. No new environment variable, secret, or permission.
To run the verification command, an engineer needs an Azure CLI login. The command is read-only.
Trade-offs
azcommand next to them is the source of truth. The list helps a reader see the current shape. The command gives the current answer.CLAUDE.md, not a gate. A future automated check could parse the mapping and compare it against the operations registry.system:note describes present behaviour, not a recommendation. The bypass inauthz/providers/azure/azure.gois recorded because it hides this class of change during testing. This PR does not propose to change it.