This file provides guidance to AI Code agents (such as claude.ai/code) when working with code in this repository.
This is a Kubernetes controller that reconciles Developer Portal capabilities based on Kuadrant resources, such as Plan Policies. It's built using the Kubebuilder framework (v4) and operator-sdk v1.41.1.
Domain: kuadrant.io API Group: devportal.kuadrant.io Resources (v1alpha1):
APIProduct: Represents an API offering in the developer portalAPIKey: Represents a developer's request for API access (created in consumer namespace)APIKeyRequest: Shadow resource for RBAC-based request review (created in owner namespace)APIKeyApproval: API owner's decision to approve/deny access requests
RBAC Design: The project implements namespace-based RBAC for API management. Read the full design at: https://github.com/Kuadrant/kuadrant-console-plugin/blob/main/docs/designs/2026-03-26-api-management-rbac-design.md
Key concepts from the design:
- Namespace isolation: Consumers create APIKeys in their namespace, owners review APIKeyRequests in their namespace
- Shadow resources: APIKeyRequest mirrors APIKey in owner's namespace for RBAC-enforced discovery
- Cross-namespace references: APIKey references APIProduct across namespaces; APIKeyApproval references APIKey across namespaces
- Secret projection: API key values projected to status field, eliminating need for secret read permissions
- Conditions pattern: Uses conditions array (Pending/Approved/Denied/Failed/Expired) following CertificateSigningRequest pattern
make build # Build manager binary (output: bin/manager)
make run # Run controller locally (not in cluster)
make docker-build # Build docker image (IMG=controller:latest)After modifying API types in api/v1alpha1/*_types.go:
make manifests # Generate CRDs, RBAC, webhook configs
make generate # Generate DeepCopy methodsmake test # Run unit tests with coverage
make test-e2e # Run e2e tests in Kind cluster (creates/deletes cluster automatically)
go test ./internal/controller -v # Run controller tests onlymake fmt # Run go fmt
make vet # Run go vet
make lint # Run golangci-lint
make lint-fix # Run golangci-lint with auto-fixesmake install # Install CRDs to cluster
make deploy # Deploy controller to cluster
make uninstall # Remove CRDs from cluster
make undeploy # Remove controller from cluster
make local-deploy # Deploy controller from current codemake build-installer # Generate consolidated YAML with CRDs and deployment
make gateway-api-crds # Download Gateway API CRDs for testing
make setup-test-e2e # Set up Kind cluster for e2e tests if it doesn't exist
make cleanup-test-e2e # Tear down the Kind cluster used for e2e tests-
api/v1alpha1/: Kubernetes API definitions
apiproduct_types.go: APIProduct CRD schema (Spec, Status, and List types)apikey_types.go: APIKey CRD schema for consumer access requestsapikeyrequest_types.go: APIKeyRequest CRD schema for owner-side request reviewapikeyapproval_types.go: APIKeyApproval CRD schema for approval decisionsgroupversion_info.go: API group registrationzz_generated.deepcopy.go: Auto-generated DeepCopy methods
-
internal/controller/: Reconciliation logic
apiproduct_controller.go: APIProductReconciler for API product lifecycleapikey_status_controller.go: APIKeyStatusReconciler — expiry checks, condition updates, RequeueAfter schedulingapikey_secret_controller.go: APIKeySecretReconciler — creates/deletes enforcement secrets on approval/denial/expiryapikey_auto_approval_controller.go: APIKeyAutoApprovalReconciler — handles automatic approval modeapikeyrequest_controller.go: APIKeyRequestReconciler for request processing- Controllers use client.Client for K8s API access
- RBAC permissions defined via kubebuilder markers (
+kubebuilder:rbac)
-
cmd/main.go: Operator entry point
- Sets up controller-runtime Manager
- Configures metrics server (default secure HTTPS on port 8443)
- Health/readiness probes on port 8081
- Leader election support (disabled by default)
- Certificate watchers for metrics and webhooks
- HTTP/2 disabled by default for security
-
config/: Kustomize manifests
config/crd/: CRD definitionsconfig/rbac/: RBAC roles and bindingsconfig/manager/: Controller deploymentconfig/samples/: Example CR manifestsconfig/prometheus/: Prometheus ServiceMonitor
The operator follows the standard Kubernetes controller pattern with multiple reconcilers:
APIProductReconciler:
- Watches APIProduct resources
- Discovers associated PlanPolicy and AuthPolicy from HTTPRoute
- Fetches and stores OpenAPI spec
- Updates status with discovered plans and auth scheme
APIKeyStatusReconciler:
- Watches APIKey resources
- Updates conditions (Pending/Approved/Denied/Failed/Expired)
- Handles key expiration: if
spec.expiresAtis set and has passed, setsExpiredcondition - Uses
RequeueAfterto wake up exactly when a key expires
APIKeySecretReconciler:
- Watches APIKey resources
- Creates enforcement secrets when key is approved
- Deletes enforcement secrets when key is denied or expired
APIKeyAutoApprovalReconciler:
- Watches APIKey resources
- Automatically approves keys when the associated APIProduct has automatic approval mode enabled
APIKeyRequestReconciler:
- Watches APIKeyRequest resources (owner namespace)
- Handles automatic approval mode
- Syncs status with related APIKey
All controllers:
- Compare desired state (Spec) vs actual state
- Take actions to converge actual state to desired state
- Update Status to reflect observed state
- controller-runtime v0.21.0: Core controller framework
- kubebuilder: Project scaffolding and code generation
- Ginkgo/Gomega: Testing framework
- operator-sdk v1.41.1: Operator tooling
- Edit types in
api/v1alpha1/*_types.go - Run
make manifests generateto regenerate code and CRDs - Update RBAC role definitions in
config/rbac/if new permissions are needed - Update sample manifests in
config/samples/to reflect new fields
The project implements namespace-based RBAC with three personas:
- API Consumer: Creates APIKey in their namespace, can read their own APIKey status
- API Owner: Views APIKeyRequest in their namespace, creates APIKeyApproval decisions
- API Admin: Manages APIProduct resources and overall API catalog
Critical security invariants:
- Consumers CANNOT see other consumers' APIKeys (namespace isolation)
- Owners CANNOT see APIKey secrets (shadow resource pattern)
- APIKeyApproval namespace MUST match APIProduct namespace (validated by controller)
- API key values projected to status field (no secret read permissions required)
- E2e tests use Kind cluster named
developer-portal-controller-test-e2e - The cluster is automatically created/destroyed by
make test-e2e - Unit tests use controller-runtime's envtest framework
- ENVTEST binaries are managed in
bin/directory
- Local development:
make run(runs outside cluster) - In-cluster:
make deploy(requires existing Kubernetes cluster) - Docker:
make docker-build docker-push deploy IMG=<your-registry>/<image>:<tag>
VERSION: Project version (default: 0.0.1)IMG: Controller image (default: controller:latest)CONTAINER_TOOL: Container build tool (default: docker, can use podman)KIND_CLUSTER: Kind cluster name for e2e tests