Skip to content

Preserve subresource granularity in CheckAccess DataAction mapping - #22

Merged
Artem Kolomeetc (arxhive) merged 1 commit into
masterfrom
fix/msrc-128222-proxy-subresource
Aug 11, 2026
Merged

Preserve subresource granularity in CheckAccess DataAction mapping#22
Artem Kolomeetc (arxhive) merged 1 commit into
masterfrom
fix/msrc-128222-proxy-subresource

Conversation

@arxhive

@arxhive Artem Kolomeetc (arxhive) commented Aug 4, 2026

Copy link
Copy Markdown

Summary

Several Kubernetes subresources are distinct authorization targets in the upstream Kubernetes RBAC model: pods/exec, pods/attach, pods/portforward, pods/proxy, services/proxy and nodes/proxy. The CheckAccess DataAction builder mapped a request on these onto the base resource's action (for example pods/read).

This change preserves the subresource in the DataAction as <resource>/<subresource>/action, using the same mechanism already applied to pods/exec and certificatesigningrequests/nodeclient, so the authorization decision keeps the same granularity as the upstream view/edit ClusterRoles.

Changes

  • Map pods exec/attach/portforward/proxy, services/proxy and nodes/proxy to distinct <resource>/<subresource>/action DataActions.
  • Add subresource name constants.
  • Add unit tests for each subresource (aks and fleet cluster types), plus a regression test that a non-listed subresource still maps to the base action.

Testing

  • go build ./... - OK
  • gofmt -l - clean
  • golangci-lint run ./authz/providers/azure/rbac/ in ghcr.io/appscode/golang-dev:1.25 - 0 issues
  • go test ./authz/providers/azure/rbac/... ./auth/providers/azure/graph/... - all pass

Comment thread authz/providers/azure/rbac/checkaccessreqhelper.go Outdated
@arxhive Artem Kolomeetc (arxhive) changed the title fix(authz): gate pods/proxy as a distinct DataAction (MSRC 128222) fix: gate pods/proxy as a distinct DataAction Aug 10, 2026
@arxhive
Artem Kolomeetc (arxhive) force-pushed the fix/msrc-128222-proxy-subresource branch from 363ad1e to e3c8339 Compare August 10, 2026 19:03
@arxhive Artem Kolomeetc (arxhive) changed the title fix: gate pods/proxy as a distinct DataAction Preserve subresource granularity in CheckAccess DataAction mapping Aug 10, 2026

@karataliu Dong Liu (karataliu) left a comment

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.

this would introduce breaks to existing cases, consider updating release note when bumping guard version.

@weinong Weinong Wang (weinong) left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

lgtm

@karataliu

Copy link
Copy Markdown
Collaborator

how will this be impacted by #23

Several Kubernetes subresources are distinct authorization targets in the
upstream Kubernetes RBAC model: pods/exec, pods/attach, pods/portforward,
pods/proxy, services/proxy and nodes/proxy. The DataAction builder mapped a
request on these onto the base resource's action (for example pods/read).

Preserve the subresource in the DataAction as
"<resource>/<subresource>/action" so the authorization decision keeps the same
granularity as the upstream view/edit ClusterRoles, using the same mechanism
already applied to pods/exec and certificatesigningrequests/nodeclient. Add the
corresponding subresource name constants and unit tests.

Signed-off-by: Artem Kolomeetc <akolomeetc@microsoft.com>
@arxhive
Artem Kolomeetc (arxhive) force-pushed the fix/msrc-128222-proxy-subresource branch from e3c8339 to e12396e Compare August 11, 2026 17:42
@arxhive

Copy link
Copy Markdown
Author

how will this be impacted by #23

Rebased onto master after #23 merged. #23 reverted #12, which removed the securitySensitiveSubresources map and restored the inline exec check in getResourceAndAction. This PR reintroduces the map form of getResourceAndAction, but scoped to pod exec/attach/portforward/proxy, services/proxy and nodes/proxy only. It does not re-add the certificatesigningrequests/nodeclient entry that #23 reverted, so the CSR behavior on master is unchanged. pods/exec keeps the same output as the current inline check. Conflict resolved in e12396e; build, lint and unit tests pass.

@arxhive

Copy link
Copy Markdown
Author

this would introduce breaks to existing cases, consider updating release note when bumping guard version.

Agreed - this is a behavioral change: a GET on pods exec/attach/portforward/proxy, services/proxy and nodes/proxy now maps to //action instead of the base /read. Callers that relied on the collapsed mapping need the corresponding data action granted.

docs/CHANGELOG.md is auto-generated (frozen at v0.6.2) and versioning is git-tag driven, so the note belongs in the AKS guard version-bump rather than a hand edit here. I will flag it as a breaking change in that bump. Let me know if you would prefer it captured somewhere in-repo as well.

@weinong Weinong Wang (weinong) left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

lgtm

Comment on lines +269 to +290
var securitySensitiveSubresources = map[string]map[string]struct{}{
PodsResource: {
ExecSubresource: {},
AttachSubresource: {},
PortForwardSubresource: {},
ProxySubresource: {},
},
ServicesResource: {
ProxySubresource: {},
},
NodesResource: {
ProxySubresource: {},
},
}

if resource == PodsResource && subResource == "exec" {
action = path.Join(resource, subResource, "action")
} else {
action = path.Join(resource, getActionName(verb))
func getResourceAndAction(resource string, subResource string, verb string) string {
if subs, ok := securitySensitiveSubresources[resource]; ok && subResource != "" {
if _, sensitive := subs[subResource]; sensitive {
return path.Join(resource, subResource, "action")
}
}

return action
return path.Join(resource, getActionName(verb))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is not the right approach. It should be inverted to define what is safe (i.e. the status sub-resource), not what is unsafe.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed, and the history of this list makes the point - it grew from exec to nodeclient to proxy to attach/portforward, each time after the gap was found rather than before. Inverted in #25.

The safe set is taken from the upstream view ClusterRole (bootstrappolicy.viewRules), which grants exactly these subresource kinds alongside their parent: status, scale, and pods/log. So safeSubresources = {status, scale, log, logs} and everything else gets //action. Wildcard requests and the special verbs (bind/escalate/use/impersonate) keep their current mapping, since there the verb rather than the subresource identifies the operation.

Two consequences worth your eye, both called out in the PR:

  1. The Microsoft.ContainerService registry currently defines only managedClusters/pods/{read,write,delete} and pods/exec/action, so anything off the safe list matches only wildcard-bearing roles and is denied for roles that enumerate leaf actions. Fail-closed as intended, but a behavioral change.
  2. It also re-gates the CSR subresources (approval/approvals, and the same rule would cover nodeclient). Revert "fix: CSR subresource action collapse allowing unauthorized kubelet certificate issuance"聽#23 reverted fix: CSR subresource action collapse allowing unauthorized kubelet certificate issuance聽#12 which had gated nodeclient, so this partially re-applies what that revert removed. If CSR should stay collapsed until those DataActions exist, I will add them to the safe set explicitly.

@arxhive
Artem Kolomeetc (arxhive) merged commit b1f9643 into master Aug 11, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants