This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Go-based Kubernetes validating/mutating webhooks framework for OpenShift Dedicated (OSD) and ROSA managed clusters. Implements 25+ webhooks that enforce security policies and operational constraints.
Primary Purpose: Prevent managed cluster users from modifying protected namespaces, resources, and configurations while allowing authorized SRE and system operations.
# Development
make test # Run tests and webhook validation
make build # Build binary
make vet # Run linter
make coverage # Generate coverage report
# Resource Generation
make syncset # Generate SelectorSyncSet YAML for Classic → build/selectorsyncset.yaml
make package # Generate Package Operator for HyperShift → build/package/*
make docs # Generate webhook documentation → docs/webhooks.json
make generate # Update namespace lists from ConfigMaps → pkg/config/namespaces.go
# Container Images
make build-image # Build container image for Classic
make build-package-image # Build PKO package for HyperShift
make build-base # Build both images
make push-base # Push both images
# Local Testing - See README.md "Local Live Testing" section for full guide
make test-webhook WEBHOOK=namespace
go test ./pkg/webhooks/namespace/... -v- Interface-Based: All webhooks implement
Webhookinterface in pkg/webhooks/register.go - Factory Pattern: Webhooks register via
init()inadd_*.gofiles - Centralized Dispatcher: Single HTTP server routes to webhooks by URI
- Plugin System: Self-contained modules in
pkg/webhooks/*/
- OSD/ROSA Classic: DaemonSet via SelectorSyncSet to master nodes
- ROSA HyperShift: Package Operator (PKO) to hosted control plane
- Control: Each webhook has
ClassicEnabled()andHypershiftEnabled()methods
- cmd/main.go - HTTP server with TLS, metrics, webhook routing
- pkg/dispatcher/ - Thread-safe request routing
- pkg/webhooks/ - 25+ webhook implementations
- pkg/config/namespaces.go - Protected namespaces (auto-generated)
- build/resources.go - Dynamic resource generation
See ls pkg/webhooks/ for full list. Key ones:
namespace- Core namespace protectionregularuser- Regular user validationpod- Privileged pod operationsservice- AWS ELB tagging (mutating)scc- SecurityContextConstraints protectioningresscontroller- Ingress protection
See README.md sections "Adding New Webhooks" and "Development" for detailed guide.
Quick Steps:
- Create
pkg/webhooks/mywebhook/mywebhook.goimplementingWebhookinterface - Create
pkg/webhooks/add_mywebhook.goregistration file - Write tests in
mywebhook_test.gousingpkg/testutilshelpers - Run
make syncset && make package && make docs && make test
Key Interface Methods:
Name()- Must be unique, end with-validationor-mutationGetURI()- Must be unique pathAuthorized()- Core webhook logic and authorizationValidate()- Request structure validationRules()- K8s admission rules (resources, operations, API groups)ClassicEnabled()/HypershiftEnabled()- Deployment targets- See pkg/webhooks/register.go for full interface
Naming Convention: Build system auto-detects webhook type by name suffix:
-validation→ ValidatingWebhookConfiguration-mutation→ MutatingWebhookConfiguration
Common patterns in Authorized() method:
// Pattern 1: Allow cluster admins and SRE, deny regular users
if utils.IsClusterAdmin(request) || utils.IsInSREGroup(request) {
return admissionctl.Allowed("Authorized")
}
return admissionctl.Denied("Regular users cannot modify this resource")
// Pattern 2: Check privileged service accounts
if utils.IsPrivilegedServiceAccount(request) {
return admissionctl.Allowed("Privileged service account")
}
// Pattern 3: Namespace pattern checks
if strings.HasPrefix(namespace, "openshift-") && !utils.IsInSREGroup(request) {
return admissionctl.Denied("Cannot modify openshift-* namespace")
}Authorization Hierarchy (highest to lowest privilege):
- Cluster Admins -
utils.IsClusterAdmin()-kube:admin,system:admin,backplane-cluster-admin - SRE Groups -
utils.IsInSREGroup()-system:serviceaccounts:openshift-backplane-srep - Privileged ServiceAccounts -
utils.IsPrivilegedServiceAccount()- System service accounts - Layered Product Admins -
utils.IsLayeredProductAdmin()-redhat-.*namespace access - Regular Users - All others, strictest validation
See README.md "Writing Unit Tests" and "Local Live Testing" for full guide.
Unit Testing:
- Use
pkg/testutilshelpers:CreateFakeRequestJSON(),SendHTTPRequest() - Test all authorization levels (cluster-admin, SRE, privileged SA, regular users)
- Test validation logic for allowed and denied operations
Test User Categories:
- Cluster admins
- SRE groups
- Privileged service accounts
- Regular users
Validation: make test validates URI uniqueness and interface compliance
- Command:
make syncset - Output: build/selectorsyncset.yaml
- Control exclusions: Edit
SELECTOR_SYNC_SET_HOOK_EXCLUDESin Makefile
- Command:
make package - Output:
build/package/* - Control exclusions: Edit
PACKAGE_HOOK_EXCLUDESin Makefile
- Command:
make generate - Output: pkg/config/namespaces.go
- Source: OpenShift ConfigMaps (
openshift-config/openshift-install,openshift-config/openshift-update)
120+ namespaces auto-generated from ConfigMaps with patterns:
^redhat-.*- Red Hat managed^openshift-.*- OpenShift platform^kube-.*- Kubernetes system- Plus:
default,openshift,kube-system
Generated in pkg/config/namespaces.go via make generate.
Edit Makefile:
SELECTOR_SYNC_SET_HOOK_EXCLUDES ?= debug-hook,unwanted-webhookThen: make syncset && make package
rm pkg/webhooks/add_mywebhook.go
rm -rf pkg/webhooks/mywebhook/
make all
# After deployment: oc delete validatingwebhookconfiguration sre-mywebhook# Check pod logs
oc logs -n openshift-validation-webhook -l app=validation-webhook
# Verify configuration
oc get validatingwebhookconfiguration
oc describe validatingwebhookconfiguration sre-<webhook-name>- Tekton Pipelines: 4 configurations in
tekton/for PR/push scenarios - App-Interface: Automated deployment via GitLab app-interface
- Registry: Quay.io/app-sre/managed-cluster-validating-webhooks (git hash tags)
- Base Image: UBI9 Linux/AMD64
- pkg/webhooks/register.go - Core interface & registration
- cmd/main.go - Main application entry point
- pkg/dispatcher/dispatcher.go - Request routing
- pkg/config/namespaces.go - Protected namespaces (generated)
- build/resources.go - Resource generation logic
- Makefile - All build/test/generation commands
- README.md - Comprehensive development guide
- Authorization First: Check authorization before expensive validation
- Clear Errors: Return actionable messages to users
- Test Coverage: Test all authorization levels and edge cases
- Timeouts: Keep
TimeoutSeconds()at 2 seconds typically - Failure Policy: Use
Ignore(fail-open) for non-critical webhooks - Unique URIs: Ensure
GetURI()is unique (validated bymake test) - Idempotency: Safe to call multiple times
- Documentation: Update
Doc()method with customer-facing explanation