Skip to content

feat(kubernetes): add AllowedAPIGroups support to toolset API - #1308

Closed
lyarwood wants to merge 1 commit into
containers:mainfrom
lyarwood:feat-allowed-api-groups
Closed

feat(kubernetes): add AllowedAPIGroups support to toolset API#1308
lyarwood wants to merge 1 commit into
containers:mainfrom
lyarwood:feat-allowed-api-groups

Conversation

@lyarwood

@lyarwood lyarwood commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Add an AllowedAPIGroupsProvider interface that allows toolsets to explicitly declare API groups that should bypass REST mapper validation in the AccessControlRoundTripper. This addresses the reviewer feedback from @Cali0707 and @manusa that exceptions to the round tripper's security model should be explicit and declared through the toolset API, not a blanket pass-through.

How it works

  • Toolset interface gains GetAllowedAPIGroups() []string
  • AllowedAPIGroupsProvider interface follows the DeniedResourcesProvider pattern exactly
  • At startup, allowed groups are collected from all enabled toolsets and stored on StaticConfig
  • The AccessControlRoundTripper checks allowed groups before rejecting requests to API groups not in the REST mapper
  • denied_resources still takes precedence for groups that ARE in the REST mapper
  • Requests to allowed virtual groups also bypass HTTP validators (schema, RBAC pre-check, and confirmation rules) since validators require a resolved GVK. The API server still enforces its own authz.
  • Empty-string groups are rejected defensively in both collectAllowedAPIGroups and isAPIGroupAllowed to prevent accidental matches against core API resources.

KubeVirt use cases

This PR adds the infrastructure. The kubevirt toolset currently returns nil from GetAllowedAPIGroups() — concrete use cases are in follow-up PRs:

Design notes

  • The pattern is intentionally identical to DeniedResourcesProvider for consistency.
  • AllowedAPIGroups has toml:"-" so it cannot be set via config files — it is computed purely from toolset code.

Testing

  • New test cases in accesscontrol_round_tripper_test.go:
    • Allowed group not in REST mapper → passes through
    • Empty-string allowed group does not match core API resources
    • Unknown group not in allowed list → rejected (existing behaviour preserved)
  • Unit tests for collectAllowedAPIGroups covering nil input, unknown toolsets, dedup, and empty-string filtering

Related

@github-actions

Copy link
Copy Markdown
Contributor

👋 Heads up — this pull request changes files owned by @aljesusg @josunect @ksimon1 @mjudeikis.

You are listed as an owner of one or more of the changed areas in .github/CODEOWNERS. GitHub cannot auto-request review from owners without write access, so this comment is the notification instead. A review when you have a moment would be appreciated 🙏

@lyarwood

Copy link
Copy Markdown
Contributor Author

@manusa @Cali0707 I'm taking another swing at allowing this to unblock the pause/unpause use cases with kubevirt. I've hopefully understood your feedback from #884 but let me know if not!

@codingben codingben left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

/lgtm

Can we get this PR merged to unblock others?

@ksimon1

ksimon1 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

@lyarwood would you please fix the formatting so the tests are happy?

@lyarwood
lyarwood force-pushed the feat-allowed-api-groups branch from b7f1a34 to edfebb8 Compare July 30, 2026 11:12
@codingben

Copy link
Copy Markdown
Contributor

@Cali0707 @manusa Can you please review it?

@ksimon1

ksimon1 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

/lgtm

@2uasimojo 2uasimojo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How does this interact with denied resources?

I don't understand how this will ever allow core resources to come through.

Comment thread pkg/kubernetes-mcp-server/cmd/root.go Outdated
}

func collectAllowedAPIGroups(toolsetNames []string) []string {
seen := make(map[string]struct{})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Consider using Set instead of rolling your own.

}
return nil, &api.ValidationError{
Code: api.ErrorCodeResourceNotFound,
Message: fmt.Sprintf("Resource %s does not exist in the cluster", api.FormatResourceName(&gvr)),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I know there's a philosophy in security-land that distinguishing between, "You're not allowed to do that," and "Daaah, I have no idea what you're talking about," supposedly gives up some kind of information that could be exploited in theory. Is that really applicable here? I can see the phone ringing with, "WDYM doesn't exist in the cluster? oc get shows it right here!"

@lyarwood

Copy link
Copy Markdown
Contributor Author

How does this interact with denied resources?

I don't understand how this will ever allow core resources to come through.

AllowedAPIGroups and denied_resources operate at completely different levels in the round tripper:

  • AllowedAPIGroups only kicks in when the REST mapper returns a NoMatchError — i.e. the resource isn't in the cluster's REST mapper at all. This is specifically for virtual/subresource API groups like subresources.kubevirt.io that never appear in the mapper. If the group bypasses that check, the request goes straight to the API server (which still enforces its own authz).
  • denied_resources is checked via isAllowed() after a successful GVK resolution, so it only applies to resources that are in the REST mapper. These two paths are mutually exclusive.

As for core API resources (pods, services, etc.) — their group is the empty string "". isAPIGroupAllowed explicitly returns false for empty-string groups, so there's no way for a toolset to accidentally whitelist core resources through this mechanism.

@2uasimojo

Copy link
Copy Markdown
Contributor

As for core API resources (pods, services, etc.) — their group is the empty string "". isAPIGroupAllowed explicitly returns false for empty-string groups, so there's no way for a toolset to accidentally whitelist core resources through this mechanism.

Right, this is my point: the default behavior appears to be to exclude (blacklist) core resources. Which might make sense for kubevirt, but is definitely Bad™ for e.g. the "core" toolset.

I guess I would have expected a design like:

  • distinguish between implemented and not-implemented (e.g. nil vs [])
  • if not implemented, there are no restrictions (including core resources)
  • if implemented, allow only specified groups, which can include "" (core)

@lyarwood
lyarwood marked this pull request as draft August 11, 2026 16:11
Add an AllowedAPIGroupsProvider interface that allows toolsets to
explicitly declare API groups that should bypass REST mapper validation
in the AccessControlRoundTripper. This enables toolsets to use virtual
API groups (e.g. subresources.kubevirt.io) that are not present in
standard API discovery without weakening the security model.

The kubevirt toolset declares subresources.kubevirt.io as an allowed
group, unblocking pause/unpause and guest agent subresource operations.

Resolves: containers#1307

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Lee Yarwood <lyarwood@redhat.com>
@lyarwood

Copy link
Copy Markdown
Contributor Author

Closing in favour of #1361, which solves the same problem at the round tripper level via a discovery fallback — no toolset changes required. I've tested the pause/unpause use case from #1306 on top of #1361 and it works correctly on OCP. There is one issue with #1361 on clusters that use aggregated discovery (OCP 4.x) that I've commented on there.

@lyarwood lyarwood closed this Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(kubernetes): add AllowedAPIGroups support to toolset API for AccessControlRoundTripper

4 participants