Skip to content

Commit 94434cd

Browse files
authored
Merge pull request #5482 from camilamacedo86/namespaced-webhook
✨ (go/v4): Add webhook scope mismatch warning for namespace-scoped mode
2 parents beef9d8 + f3e3f6b commit 94434cd

File tree

4 files changed

+71
-2
lines changed

4 files changed

+71
-2
lines changed

docs/book/src/migration/namespace-scoped.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,24 @@ kubectl apply -f config/samples/ -n <manager-namespace>
270270
kubectl apply -f config/samples/ -n other-namespace
271271
```
272272

273+
<aside class="warning">
274+
275+
<h1>Webhooks and Namespace-Scoped Mode</h1>
276+
277+
If your project has webhooks, the manager cache is restricted to `WATCH_NAMESPACE`, but webhooks receive requests from all namespaces by default.
278+
279+
**The Problem:**
280+
281+
Your webhook server receives admission requests from all namespaces, but the cache only has data from `WATCH_NAMESPACE`. If a webhook handler queries the cache for an object outside the watched namespaces, the lookup fails.
282+
283+
**Solution:**
284+
285+
Configure `namespaceSelector` or `objectSelector` on your webhooks to align webhook scope with the cache. Currently, controller-gen does not have markers for this. You must add these manually using Kustomize patches.
286+
287+
See the [Webhook Bootstrap Problem](../reference/webhook-bootstrap-problem.html) guide for detailed steps on creating and applying namespace selector patches.
288+
289+
</aside>
290+
273291
## AI-Assisted Migration
274292

275293
If you're using an AI coding assistant (Cursor, GitHub Copilot, etc.), you can automate the manual migration steps.
@@ -486,11 +504,11 @@ This command automatically:
486504
## Important Notes
487505

488506
- **Only controllers need RBAC updates**: Only update `+kubebuilder:rbac` markers in controller files (files with `Reconcile` function). Webhook files do NOT use RBAC markers - webhooks use certificate-based authentication with the API server.
489-
- **Webhooks remain cluster-scoped**: `ValidatingWebhookConfiguration` and `MutatingWebhookConfiguration` are cluster-scoped resources that validate/mutate CRs in all namespaces. This is correct - webhooks enforce schema consistency across the cluster, while controllers (namespace-scoped) only reconcile resources in their watched namespace(s).
490507
- **RBAC markers control scope**: The `namespace=` parameter in controller RBAC markers determines whether controller-gen generates `Role` (namespace-scoped) or `ClusterRole` (cluster-scoped). Without the `namespace=` parameter, controller-gen always generates `ClusterRole`.
491508
- **Controller-gen regenerates role.yaml**: After running `make manifests`, controller-gen will regenerate `config/rbac/role.yaml` based on your controller RBAC markers. The initial `Role` scaffold from `kubebuilder edit --namespaced=true` serves as a template, but controller-gen manages the actual content.
492509
- **Namespace parameter format**: Use `namespace=<your-namespace>` in controller RBAC markers, typically `namespace=<project-name>-system` to match your deployment namespace.
493510
- **Metrics auth role stays cluster-scoped**: The `metrics-auth-role` uses cluster-scoped APIs (TokenReview, SubjectAccessReview) and correctly remains a ClusterRole without namespace parameter.
511+
- **Webhooks require manual configuration**: Currently, controller-gen does not support `namespaceSelector` or `objectSelector` markers for webhooks. See the webhook section above for details.
494512

495513
## See Also
496514

docs/book/src/reference/manager-scope.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,24 @@ The `testdata/project-v4-with-plugins` in the Kubebuilder repository demonstrate
145145
See: [testdata/project-v4-with-plugins](https://github.com/kubernetes-sigs/kubebuilder/tree/master/testdata/project-v4-with-plugins)
146146
</aside>
147147

148+
<aside class="warning">
149+
150+
<h1>Webhooks and Namespace-Scoped Mode</h1>
151+
152+
If your project has webhooks, the manager cache is restricted to `WATCH_NAMESPACE`, but webhooks receive requests from all namespaces by default.
153+
154+
**The Problem:**
155+
156+
Your webhook server receives admission requests from all namespaces, but the cache only has data from `WATCH_NAMESPACE`. If a webhook handler queries the cache for an object outside the watched namespaces, the lookup fails.
157+
158+
**Solution:**
159+
160+
Configure `namespaceSelector` or `objectSelector` on your webhooks to align webhook scope with the cache. Currently, controller-gen does not have markers for this. You must add these manually using Kustomize patches.
161+
162+
See the [Webhook Bootstrap Problem](../reference/webhook-bootstrap-problem.html) guide for detailed steps on creating and applying namespace selector patches.
163+
164+
</aside>
165+
148166
## See Also
149167

150168
- [Understanding Scopes](./scopes.md) - Overview of manager and CRD scopes

pkg/plugins/golang/v4/edit.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,21 @@ Multigroup (--multigroup):
4848
Changes API structure: api/<version>/ becomes api/<group>/<version>/
4949
Automatic: Updates PROJECT file, future APIs use new structure
5050
Manual: Move existing API files, update import paths in controllers
51-
Migration guide: https://book.kubebuilder.io/migration/multi-group.html
51+
More info: https://book.kubebuilder.io/migration/multi-group.html
5252
5353
Namespaced (--namespaced):
5454
Enable or disable namespace-scoped deployment.
5555
Manager watches one or more specific namespaces vs all namespaces.
5656
Namespaces to watch are configured via WATCH_NAMESPACE environment variable.
5757
Automatic: Updates PROJECT file, scaffolds Role/RoleBinding, uses --force to regenerate manager.yaml
5858
Manual: Add namespace= to RBAC markers in existing controllers, update cmd/main.go, run 'make manifests'
59+
More info: https://book.kubebuilder.io/migration/namespace-scoped.html
60+
61+
WARNING - Webhooks and Namespace-Scoped Mode:
62+
Webhooks remain cluster-scoped even in namespace-scoped mode.
63+
The manager cache is restricted to WATCH_NAMESPACE, but webhooks receive requests
64+
from ALL namespaces. You must configure namespaceSelector or objectSelector to align
65+
webhook scope with the cache.
5966
6067
Force (--force):
6168
Overwrite existing scaffolded files to apply configuration changes.

pkg/plugins/golang/v4/scaffolds/edit.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package scaffolds
1818

1919
import (
2020
"fmt"
21+
log "log/slog"
2122

2223
"github.com/spf13/afero"
2324

@@ -91,6 +92,12 @@ func (s *editScaffolder) Scaffold() error {
9192
fmt.Println("Run with --force to update config/manager/manager.yaml with WATCH_NAMESPACE")
9293
}
9394

95+
// Check if project has webhooks and warn about scope mismatch
96+
if s.hasWebhooks() {
97+
log.Warn("your project has webhooks which are cluster-scoped.\n" +
98+
"You will need to manually configure namespaceSelector or objectSelector")
99+
}
100+
94101
// Print next steps
95102
fmt.Println()
96103
fmt.Println("Next steps:")
@@ -99,6 +106,11 @@ func (s *editScaffolder) Scaffold() error {
99106
fmt.Printf(" // +kubebuilder:rbac:groups=mygroup,resources=myresources,verbs=get;list,"+
100107
"namespace=%s-system\n", s.config.GetProjectName())
101108
fmt.Println("3. Run: make manifests")
109+
110+
if s.hasWebhooks() {
111+
fmt.Println("4. Configure namespaceSelector or objectSelector for webhooks")
112+
}
113+
102114
fmt.Println()
103115
fmt.Println("See: https://book.kubebuilder.io/migration/namespace-scoped.html")
104116
} else if !s.namespaced && wasNamespaced {
@@ -155,3 +167,17 @@ func (s *editScaffolder) scaffoldClusterRBAC(force bool) error {
155167
}
156168
return nil
157169
}
170+
171+
// hasWebhooks checks if any resources in the project have webhooks configured
172+
func (s *editScaffolder) hasWebhooks() bool {
173+
resources, err := s.config.GetResources()
174+
if err != nil {
175+
return false
176+
}
177+
for _, res := range resources {
178+
if res.Webhooks != nil && !res.Webhooks.IsEmpty() {
179+
return true
180+
}
181+
}
182+
return false
183+
}

0 commit comments

Comments
 (0)