Skip to content

Add an option to prevent caching of resources in other namespaces#6732

Merged
jbw976 merged 2 commits intocrossplane:mainfrom
orange-cloudfoundry:restricted-cache-option
Jan 28, 2026
Merged

Add an option to prevent caching of resources in other namespaces#6732
jbw976 merged 2 commits intocrossplane:mainfrom
orange-cloudfoundry:restricted-cache-option

Conversation

@frigaut-orange
Copy link
Copy Markdown
Contributor

@frigaut-orange frigaut-orange commented Aug 19, 2025

Description of your changes

Add a --restrict-cache-options config flag in core cmd to avoid caching resources from other namespaces (and prevent crashes when crossplane does not have permissions on other namespaces)

Fixes #6348

I have:

Need help with this checklist? See the cheat sheet.

Copy link
Copy Markdown
Member

@negz negz left a comment

Choose a reason for hiding this comment

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

Whoops sorry I missed this. The change in general LGTM but I'd like to think about the flag name.

@jbw976 @phisco @bobh66 any suggestions?

@negz negz closed this Oct 7, 2025
@negz negz reopened this Oct 7, 2025
@negz
Copy link
Copy Markdown
Member

negz commented Oct 7, 2025

(Closed and re-opened to trigger CI run.)

@frigaut-orange frigaut-orange force-pushed the restricted-cache-option branch from 729327a to 04d6a49 Compare October 29, 2025 09:25
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Oct 29, 2025

📝 Walkthrough

Walkthrough

Added a public WatchCacheNamespaced bool to the controller start command and changed manager cache initialization to build cache.Options (with SyncPeriod) and, when WatchCacheNamespaced is true, set DefaultNamespaces to the controller's namespace to restrict resource watches.

Changes

Cohort / File(s) Change Summary
Namespaced cache configuration
cmd/crossplane/core/core.go
Added exported field WatchCacheNamespaced bool to startCommand. Introduced cacheOptions and cacheOptionsAPIExt in Run with SyncPeriod, conditionally set DefaultNamespaces to the controller namespace when WatchCacheNamespaced is true, and updated manager and API-extension cache creation to use these options instead of inline configs.
Manifest reference
go.mod
Listed in manifest; no functional changes shown in diff summary.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Controller as Crossplane Controller (startCommand.Run)
    participant Manager as controller-runtime Manager
    participant Cache as controller-runtime Cache

    User->>Controller: start (flag: --watch-cache-namespaced true|false)
    activate Controller
    Controller->>Controller: build cacheOptions (SyncPeriod)
    alt WatchCacheNamespaced == true
        Controller->>Controller: set cacheOptions.DefaultNamespaces = [controllerNamespace]
        Controller->>Controller: set cacheOptionsAPIExt.DefaultNamespaces = [controllerNamespace]
    end
    Controller->>Manager: New(manager.Options{Cache: cacheOptions})
    Manager->>Cache: initialize with cacheOptions / cacheOptionsAPIExt
    Cache-->>Manager: cache started (namespaced or cluster-wide)
    Manager-->>Controller: manager ready
    deactivate Controller
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Areas to focus:
    • Confirm DefaultNamespaces is set to the correct runtime namespace value.
    • Verify both manager and API-extension caches receive the intended cache.Options.
    • Check exported field naming, CLI flag wiring, and any tests or docs that should reflect the new option.

Would you like me to also suggest the CLI flag name and a Helm values change to expose this option, or keep that in a follow-up PR?

Pre-merge checks

✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and descriptively summarizes the main change: adding an option to prevent caching of resources in other namespaces, which directly aligns with the pull request's objective.
Description check ✅ Passed The description is directly related to the changeset, explaining the purpose of the new flag and its connection to issue #6348.
Linked Issues check ✅ Passed The PR implements the core coding requirement from #6348 by adding a flag to restrict cache to the current namespace, directly addressing the namespaced mode objective.
Out of Scope Changes check ✅ Passed All changes are scoped to the stated objective: a new boolean field and cache configuration logic to support namespace-restricted caching.
Breaking Changes ✅ Passed PR adds optional WatchCacheNamespaced field and CLI flag to startCommand struct. Changes are additive, backward-compatible, and inert unless explicitly enabled by user.
Feature Gate Requirement ✅ Passed The PR adds a command-line flag (--restrict-cache-options) that gates new caching behavior, making it opt-in. The change does not modify apis/** and implements feature flagging appropriately.

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 564046c and a4d3823.

📒 Files selected for processing (1)
  • cmd/crossplane/core/core.go (4 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
{apis,cmd}/**

📄 CodeRabbit inference engine (Custom checks)

Files under 'apis/' or 'cmd/' must not remove or rename public fields/flags, add new required public fields/flags, or remove behavior without including the 'breaking-change' label

Files:

  • cmd/crossplane/core/core.go
**/*.go

⚙️ CodeRabbit configuration file

**/*.go: Enforce Crossplane-specific patterns: Use crossplane-runtime/pkg/errors
for wrapping. Check variable naming (short for local scope, descriptive
for wider scope). Ensure 'return early' pattern. Verify error scoping
(declare in conditionals when possible). For nolint directives, require
specific linter names and explanations. CRITICAL: Ensure all error
messages are meaningful to end users, not just developers - avoid
technical jargon, include context about what the user was trying to do,
and suggest next steps when possible.

Files:

  • cmd/crossplane/core/core.go
**/cmd/**

⚙️ CodeRabbit configuration file

**/cmd/**: Review CLI commands for proper flag handling, help text, and error
messages. Ensure commands follow Crossplane CLI conventions. Ask about
backward compatibility and user experience. CLI error messages must be
especially user-friendly - avoid internal error details, provide
actionable guidance.

Files:

  • cmd/crossplane/core/core.go
🧠 Learnings (3)
📓 Common learnings
Learnt from: frigaut-orange
Repo: crossplane/crossplane PR: 6732
File: cmd/crossplane/core/core.go:186-196
Timestamp: 2025-11-20T10:28:53.064Z
Learning: In PR #6732, the WatchCacheNamespaced flag is specifically intended to restrict the manager's cache to prevent permission errors on Kubernetes-native resources (Services, Deployments, ServiceAccounts, Secrets, ConfigMaps) in other namespaces. The API extensions cache used by Claim and XR controllers should NOT be restricted because Crossplane requires cluster-wide access to its own custom resources (XRs, Claims, Compositions) to function.
📚 Learning: 2025-11-20T10:28:53.064Z
Learnt from: frigaut-orange
Repo: crossplane/crossplane PR: 6732
File: cmd/crossplane/core/core.go:186-196
Timestamp: 2025-11-20T10:28:53.064Z
Learning: In PR #6732, the WatchCacheNamespaced flag is specifically intended to restrict the manager's cache to prevent permission errors on Kubernetes-native resources (Services, Deployments, ServiceAccounts, Secrets, ConfigMaps) in other namespaces. The API extensions cache used by Claim and XR controllers should NOT be restricted because Crossplane requires cluster-wide access to its own custom resources (XRs, Claims, Compositions) to function.

Applied to files:

  • cmd/crossplane/core/core.go
📚 Learning: 2025-11-25T21:57:11.518Z
Learnt from: CR
Repo: crossplane/crossplane PR: 0
File: contributing/README.md:0-0
Timestamp: 2025-11-25T21:57:11.518Z
Learning: Applies to contributing/**/*.go : Make conditions and messages actionable for Crossplane users with enough information to know where to look next, and document reasons in API docs

Applied to files:

  • cmd/crossplane/core/core.go
🔍 Remote MCP

Let me search the web for relevant Crossplane documentation and context about the caching mechanism and RBAC:Let me search for more specific information about Kubernetes controller manager caching and the implementation patterns this PR follows:

Summary of Additional Context for PR #6732 Review

Based on the search results, here is relevant context for reviewing this PR:

Problem Context

The RBAC manager runs as a distinct pod responsible for creating and binding RBAC roles, allowing Crossplane and its providers to run as service accounts limited to a specific set of resources and verbs (e.g., create, watch, etc.) However, the Crossplane Helm Chart deployments have excessive RBAC permissions beyond what they need.

Related Ecosystem Trends

Crossplane v2 makes all managed resources (MRs) namespaced, with maintainers actively working to update managed resources for other systems to support namespaced MRs. This PR aligns with the broader v2 direction toward namespace-scoped resources.

Technical Implementation Pattern

The DefaultNamespaces cache option creates a multiNamespaceCache, which internally maintains a map of namespace name to Cache (informerCache), allowing specification of Informer behavior for particular namespaces. The Manager can restrict the namespace that all controllers will watch for resources by configuring the Cache Options DefaultNamespaces.

RBAC Permissions Impact

Controllers need appropriate RBAC permissions for object kinds they retrieve via cached clients (i.e., list and watch), and by default, watches started by a controller-runtime cache are cluster-scoped, meaning it watches and caches objects across all namespaces. This PR addresses the permission issue by restricting watches to the controller's own namespace when the flag is enabled.

Cache Configuration Implications

SyncPeriod determines the minimum frequency at which watched resources are reconciled—a lower period will correct entropy more quickly, but reduce responsiveness to change if there are many watched resources. The PR's approach of configuring separate cache options with SyncPeriod allows fine-grained control over both the core controller and API extension caches.

Backward Compatibility

As noted in the PR description, the change is inert unless the new flag is explicitly specified, maintaining default behavior for existing deployments.


Sources used: Crossplane documentation and design files, Kubernetes controller-runtime documentation, and related GitHub issues and discussions discussing RBAC permissions, caching strategies, and namespace scoping patterns.

🔇 Additional comments (3)
cmd/crossplane/core/core.go (3)

142-142: LGTM - Clear and user-friendly help text!

The help text effectively communicates when and why to use this flag. The default value of false ensures backward compatibility.


186-196: LGTM - Clean implementation of namespace-scoped caching!

The implementation correctly uses DefaultNamespaces to restrict the manager's cache to Crossplane's namespace when the flag is enabled. The inline comment helpfully explains the rationale.


356-380: Verify that restricting the API extensions cache works as intended for XRs and Claims.

The implementation looks technically sound and follows the same pattern as the manager cache. However, I'd like to confirm that this has been tested and works correctly when enabled.

Based on the retrieved learnings, there was an earlier indication that the API extensions cache should maintain cluster-wide access to XRs and Claims for Crossplane to function properly. However, I see from the discussion that @negz suggested exploring whether there's a use case for restricting namespaced XRs to a single namespace, and you agreed to try it out.

Could you share the testing results? Specifically:

  • Do XR and Claim controllers still function correctly when --watch-cache-namespaced is enabled?
  • Are there any limitations users should be aware of (e.g., only works with namespaced XRs in the same namespace)?
  • Did the e2e test failure you mentioned in the PR comments relate to this change?

This verification would help ensure the feature works as expected and inform what documentation or caveats might be needed.

Based on learnings, there was concern about restricting the API extensions cache, but the maintainer suggested exploring this use case.

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@frigaut-orange frigaut-orange force-pushed the restricted-cache-option branch from 04d6a49 to 2a7a999 Compare October 29, 2025 09:25
@frigaut-orange
Copy link
Copy Markdown
Contributor Author

Changed the flag name and rebased onto main, let me know if that's good for you @negz @phisco

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1da505f and 2a7a999.

📒 Files selected for processing (1)
  • cmd/crossplane/core/core.go (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

⚙️ CodeRabbit configuration file

**/*.go: Enforce Crossplane-specific patterns: Use crossplane-runtime/pkg/errors
for wrapping. Check variable naming (short for local scope, descriptive
for wider scope). Ensure 'return early' pattern. Verify error scoping
(declare in conditionals when possible). For nolint directives, require
specific linter names and explanations. CRITICAL: Ensure all error
messages are meaningful to end users, not just developers - avoid
technical jargon, include context about what the user was trying to do,
and suggest next steps when possible.

Files:

  • cmd/crossplane/core/core.go
**/cmd/**

⚙️ CodeRabbit configuration file

**/cmd/**: Review CLI commands for proper flag handling, help text, and error
messages. Ensure commands follow Crossplane CLI conventions. Ask about
backward compatibility and user experience. CLI error messages must be
especially user-friendly - avoid internal error details, provide
actionable guidance.

Files:

  • cmd/crossplane/core/core.go
🔍 Remote MCP

I'll search for additional context about Crossplane's caching architecture and the namespaced cache feature to help with your PR review.Based on my research, I've gathered comprehensive context about Crossplane's architecture, caching mechanisms, and RBAC model. Here's the relevant context for reviewing PR #6732:

Context for PR #6732 Review

Problem Context: Cache and Permissions Issues

The Crossplane controller faces caching challenges where resource leaks occur when the local cache is not updated quickly enough after large numbers of resources are created, causing subsequent reconciliations to not find created resources in the cache and create new resources instead. This PR addresses a more specific issue: disabling caching of Kubernetes-native resources when the controller lacks cluster-wide permissions.

Architectural Context: RBAC and Cluster-Scoped Resources

The base Crossplane installation consists of two pods—the crossplane pod and the crossplane-rbac-manager pod—both installed in the crossplane-system namespace by default. The Crossplane RBAC manager pod automates required Kubernetes RBAC permissions for Crossplane and Providers; Crossplane installs and enables the RBAC manager by default, and disabling it requires manual Kubernetes permissions definitions for proper Crossplane operations.

Design Direction: Future Namespacing

The PR's approach aligns with Crossplane's roadmap. In Crossplane v2, all Managed Resources are proposed to become namespaced; someday all MRs are expected to be namespaced, with cluster-scoped MRs becoming legacy for v1 backward compatibility, though cluster-scoped resource support is needed for a long migration period.

Related Caching Precedents

A related PR disabled caching of Unstructured resources for claims and XRs to address similar resource leaks, suggesting precedent for selective caching configuration in Crossplane.

Test Coverage Note

The PR checklist indicates no unit or e2e tests were added, which is notable given the medium complexity of the change and the critical nature of caching behavior to controller stability.

[::web_search::]

🔇 Additional comments (2)
cmd/crossplane/core/core.go (2)

179-193: Nice implementation of namespace-scoped caching!

The logic correctly restricts cache watches to Crossplane's namespace when the flag is enabled, which should prevent the permission-related crashes described in issue #6348. The backward-compatible default ensures existing deployments aren't affected.


344-362: No action required – the separate cache design is correct.

The separate cache created for the ControllerEngine (lines 344-362) doesn't need the WatchCacheNamespaced restriction. Here's why:

  1. Different caches, different concerns: The main manager cache (lines 182-189) watches native Kubernetes resources like ServiceAccounts, Services, and Secrets—which is where permission errors occur. The separate ca cache watches only Crossplane-specific CRDs: Claims, CompositeResources, ComposedResources, and CompositionRevisions.

  2. Intentional cluster-wide scope: The ControllerEngine cache needs exclusive ownership and cluster-wide visibility to dynamically track which controllers are using which informers. XRs are cluster-scoped resources, and the cache must discover all composed resources across all namespaces to manage them correctly.

  3. Correct configuration: The cache explicitly caches unstructured resources (XRs and MRs) and excludes Secrets—exactly what it should do for API extension management.

The PR correctly applies the namespace restriction to the main manager cache (which watches native K8s resources) while leaving the ControllerEngine cache unrestricted (which watches Crossplane CRDs). This design is sound.

@negz
Copy link
Copy Markdown
Member

negz commented Nov 19, 2025

Ah, looks like merging the other PR caused a conflict for this one.

Signed-off-by: François Rigaut <francois.rigaut@orange.com>
@frigaut-orange frigaut-orange force-pushed the restricted-cache-option branch from 2a7a999 to 564046c Compare November 20, 2025 10:07
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
cmd/crossplane/core/core.go (2)

142-142: Clear and helpful flag addition!

The field declaration and help text look great. The help text is user-friendly and clearly explains when to use this option, which aligns well with the coding guidelines for CLI commands.

One optional suggestion: Consider mentioning in the help text what functionality might be limited when this flag is enabled (e.g., "Resources in other namespaces will not be watched or cached"). This would help users make informed decisions about enabling it.

Optional improvement to help text
-	WatchCacheNamespaced     bool `default:"false" help:"Restrict resource caching to Crossplane's namespace only. Use this when Crossplane lacks cluster-wide permissions."`
+	WatchCacheNamespaced     bool `default:"false" help:"Restrict resource caching to Crossplane's namespace only; resources in other namespaces will not be watched or cached. Use this when Crossplane lacks cluster-wide permissions."`

186-196: Consider adding tests for this crash-prevention feature

Since this feature addresses a crash scenario when Crossplane lacks cluster-wide permissions (as mentioned in issue #6348), it would be valuable to add tests verifying that:

  1. The cache correctly restricts to the specified namespace when the flag is enabled
  2. The controller doesn't crash when permissions are limited

I understand tests weren't included in this PR, but they would increase confidence that this feature works as intended and prevent regressions.

Would you like to add tests in this PR, or would you prefer to track them separately?

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a7a999 and 564046c.

📒 Files selected for processing (1)
  • cmd/crossplane/core/core.go (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

⚙️ CodeRabbit configuration file

**/*.go: Enforce Crossplane-specific patterns: Use crossplane-runtime/pkg/errors
for wrapping. Check variable naming (short for local scope, descriptive
for wider scope). Ensure 'return early' pattern. Verify error scoping
(declare in conditionals when possible). For nolint directives, require
specific linter names and explanations. CRITICAL: Ensure all error
messages are meaningful to end users, not just developers - avoid
technical jargon, include context about what the user was trying to do,
and suggest next steps when possible.

Files:

  • cmd/crossplane/core/core.go
**/cmd/**

⚙️ CodeRabbit configuration file

**/cmd/**: Review CLI commands for proper flag handling, help text, and error
messages. Ensure commands follow Crossplane CLI conventions. Ask about
backward compatibility and user experience. CLI error messages must be
especially user-friendly - avoid internal error details, provide
actionable guidance.

Files:

  • cmd/crossplane/core/core.go
🔇 Additional comments (1)
cmd/crossplane/core/core.go (1)

186-196: Manager cache configuration looks good!

The cache options configuration is well-structured and the conditional logic correctly restricts the cache to Crossplane's namespace when the flag is enabled. The comment clearly explains the reasoning.

@frigaut-orange
Copy link
Copy Markdown
Contributor Author

@negz I rebased and fixed conflicts.

@frigaut-orange
Copy link
Copy Markdown
Contributor Author

There is a failure in e2e tests, however I cannot replicate it locally. Since my code supposedly does not change Crossplane's behavior unless specified with the added argument, I'd say this is a timeout shenanigan in Github actions, but feel free to correct me if I'm wrong.

Signed-off-by: François Rigaut <francois.rigaut@orange.com>
@frigaut-orange
Copy link
Copy Markdown
Contributor Author

@negz Up - could you please tell me if this PR is ok ?

@AlexanderSing
Copy link
Copy Markdown

Hi, thanks for the great work, this feature is almost exactly what we're looking for as well. I've got just one additional request: Would it be possible to also configure which namespaces are being watched? I had something like this in mind:

if len(c.WatchCacheNamespaces) > 0 {
    nsMap := make(map[string]cache.Config)
    for _, ns := range c.CacheNamespaces {
        nsMap[ns] = cache.Config{}
    }
    cacheOptionsAPIExt.DefaultNamespaces = nsMap
}

with WatchCacheNamespaces a list of namespaces, instead of / alternative to your

if c.WatchCacheNamespaced {
	cacheOptionsAPIExt.DefaultNamespaces = map[string]cache.Config{
		c.Namespace: {},
	}
}

I am not experienced with the implications this has, thus any feedback / input to this suggestion is welcome!

@frigaut-orange
Copy link
Copy Markdown
Contributor Author

frigaut-orange commented Jan 15, 2026

Hello,

I'm all for it, we also suggested something very similar in external-secrets (external-secrets/external-secrets#4721)

Here the goal is to restrict Crossplane's cache in a namespace-restricted way according to the philosophy of this design doc (which is a little outdaded regarding the name of the options, etc.). Also I would have to test if it keeps reconciling resources correctly on all namespaces.

And before doing that, having the insight of a maintainer may be useful

Copy link
Copy Markdown
Member

@jbw976 jbw976 left a comment

Choose a reason for hiding this comment

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

Thank you @frigaut-orange for continuing to drive these namespace restriction changes. This change looks focused and clean to do what it advertises ✅

I haven't been keeping up with the broader effort, but I know you would like to get this PR merged, so I'm catching up a bit now and trying to help with that.

It sounds like from #6425 (comment) that this is one step towards the broader picture outlined in the namespace restricted mode design doc.

Merging this doesn't invalidate #6425, it's more of a step along the way and would need to be absorbed into that effort if I understand correctly.

I'm hesitant to update this specific PR at this point to start handling multiple namespaces of the users choosing (instead of just the core crossplane namespace), because I think that has knock on effects in other places and should be thought of more completely in the context of the general namespace restriction design.

Let's get this merged and revisit the effort in its entirety to figure out clear next steps 🙇‍♂️

@jbw976 jbw976 merged commit 63bb14e into crossplane:main Jan 28, 2026
25 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.

Enable a namespaced mode for the crossplane controller pod

6 participants