A Kubernetes Cluster API control plane provider that enables management of hosted control planes as first-class Kubernetes resources. This provider allows you to create and manage highly available Kubernetes control plane components (API Server, Controller Manager, Scheduler, and etcd) as hosted services, decoupling them from the underlying infrastructure.
Traditional Kubernetes clusters tightly couple the control plane components with worker nodes on the same infrastructure. Hosted control planes break this coupling by running control plane components as managed services, offering:
- Infrastructure Independence: Control planes run separately from worker nodes
- Enhanced Reliability: Dedicated infrastructure for control plane components
- Simplified Operations: Automated lifecycle management and upgrades
- Cost Optimization: Shared control plane infrastructure across multiple clusters
- Faster Provisioning: Pre-provisioned control planes reduce cluster creation time
- Multi-Replica Control Plane: Horizontal scaling for high availability
- Automated ETCD Management: Built-in backup/restore with S3 integration
- Gateway API Integration: Modern traffic routing and load balancing
- Certificate Management: Automated TLS via cert-manager integration
- OpenTelemetry Observability: Comprehensive tracing and monitoring
- Cloud-Native Storage: S3-compatible backup solutions
- Network Policy Support: Component-based access control with automatic policy generation
- When Cilium is detected, Cilium Network Policies are created instead of vanilla Kubernetes Network Policies (recommended)
- Cilium policies provide enhanced capabilities such as DNS-based filtering, allowing workload pods to communicate only with their specific control plane endpoints
- Falls back to vanilla Kubernetes Network Policies when Cilium is not available
graph TB
subgraph MC["ποΈ Management Cluster"]
subgraph HCP["ποΈ Hosted Control Plane"]
direction TB
subgraph CP["Control Plane Components"]
direction LR
API["π‘ API Server"]
CM["π§ Controller Manager"]
SCHED["β° Scheduler"]
API --- CM --- SCHED
end
ETCD["πΎ ETCD Cluster"]
CP --- ETCD
end
CAPI["π€ Cluster API"]
PROVIDER["π HCP Provider"]
end
subgraph WC["π¨ Workload Cluster"]
direction LR
W1["π· Worker Node 1"]
W2["π· Worker Node 2"]
WN["π· Worker Node N"]
W1 --- W2 --- WN
end
HCP -->|"π Kubeconfig"| WC
CAPI --> PROVIDER
PROVIDER --> HCP
style MC fill:#e1f5fe,color:#000
style HCP fill:#f3e5f5,color:#000
style WC fill:#e8f5e8,color:#000
style API fill:#fff3e0,color:#000
style CM fill:#fff3e0,color:#000
style SCHED fill:#fff3e0,color:#000
style ETCD fill:#fce4ec,color:#000
- Kubernetes cluster (management cluster) v1.28+
- Cluster API v1.11+ installed
- cert-manager v1.18+ for certificate management
- Gateway API v1.3+ CRDs installed
- A Gateway with a TLS wildcard listener (see Gateway and DNS Configuration)
The provider requires a Gateway with a TLS listener using a wildcard hostname. This is used to route traffic to hosted control planes.
Create a Gateway with a TLS passthrough listener:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: capi
namespace: capi-system
spec:
gatewayClassName: your-gateway-class # e.g., cilium, envoy, etc.
listeners:
- name: tls-passthrough
protocol: TLS
# this is the exposed port, the number here might be different
# depending on your gateway-api provider
port: 443
hostname: "*.clusters.example.com" # Must be a wildcard
tls:
mode: Passthrough
allowedRoutes:
namespaces:
from: AllImportant: The listener must use:
protocol: TLS(not HTTPS)- A wildcard hostname (e.g.,
*.clusters.example.com) tls.mode: Passthroughto allow the API server to terminate TLS
Configure DNS to resolve the wildcard domain to your Gateway's external IP/hostname.
Each cluster gets an endpoint derived from the wildcard:
<cluster-name>.<cluster-namespace>.<wildcard-domain>
For example, with hostname *.clusters.example.com:
- Cluster
prodin namespacedefaultβprod.default.clusters.example.com - Cluster
stagingin namespaceteam-aβstaging.team-a.clusters.example.com
Konnectivity subdomain: The Konnectivity server (used for node-to-control-plane communication) requires an
additional konnectivity. prefix:
konnectivity.<cluster-name>.<cluster-namespace>.<wildcard-domain>
This means your DNS setup must handle requests like konnectivity.prod.default.clusters.example.com. Depending on your
DNS provider, you may need:
- A deeper wildcard record that matches the three-label prefix, for example:
*.*.*.clusters.example.com - Or explicit DNS records for each required Konnectivity hostname
cert-manager must be configured to enable secret owner reference propagation. This ensures that certificate secrets are properly garbage collected when the owning Certificate resource is deleted.
For more details, see the cert-manager documentation on secret owner references.
# Install using the latest release
kubectl apply -f https://github.com/teutonet/cluster-api-provider-hosted-control-plane/releases/latest/download/control-plane-components.yaml
# Or install a specific version
kubectl apply -f https://github.com/teutonet/cluster-api-provider-hosted-control-plane/releases/download/v1.5.0/control-plane-components.yamlkubectl get pods -n capi-hosted-control-plane-systemapiVersion: controlplane.cluster.x-k8s.io/v1alpha1
kind: HostedControlPlane
metadata:
name: my-hosted-control-plane
namespace: default
spec:
version: v1.33.0
replicas: 3
gateway:
# Reference to the Gateway with a TLS wildcard listener
# See "Gateway and DNS Configuration" section above
name: capi
namespace: capi-systemapiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
name: my-cluster
spec:
controlPlaneRef:
apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
kind: HostedControlPlane
name: my-hosted-control-plane
infrastructureRef:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: AWSCluster # Or your infrastructure provider
name: my-aws-cluster| Variable | Description | Default |
|---|---|---|
LEADER_ELECTION |
Enable leader election | true |
WEBHOOK_CERT_DIR |
Directory for webhook certs | /tmp/k8s-webhook-server/serving-certs |
MAX_CONCURRENT_RECONCILES |
Max concurrent reconciles | 10 |
CONTROLLER_NAMESPACE |
Namespace for the controller | |
LOG_FORMAT |
Log format (json or text) | json |
LOG_LEVEL |
Log level (debug, info, etc.) | info |
OTEL_EXPORTER_OTLP_ENDPOINT |
OpenTelemetry collector endpoint | - |
- Go 1.25+
- kubectl
- Task (for building and testing)
# Build the project
task build
# Run tests
task test
# Run linting
task lint
# Generate manifests
task manifests
# Full CI pipeline
task ci# have CAPI installed
task manifests
kubectl apply -f ./build/control-plane-components.yaml
task dev
# Run the controller locally within you IDE (.run for IDEA provided)We welcome contributions! Please see our Contributing Guide for details on:
- Code of Conduct
- Development process
- Pull request guidelines
- Issue reporting
- Fork the repository
- Create a feature branch (
git switch -c feature/amazing-feature) - Make your changes
- Run tests and linting (
task ci) - Commit your changes (
git commit) - Push to the branch (
git push fork feature/amazing-feature) - Open a Pull Request (
gh pr createis amazing!)
| Component | Version |
|---|---|
| Kubernetes | v1.28+ |
| Cluster API | v1.11+ |
| cert-manager | v1.18+ |
| Gateway API | v1.3+ |
| Go | 1.25+ |
- Enhanced Monitoring: Prometheus metrics
- Auto-Scaling: Dynamic control plane scaling based on load
- GitHub Issues: Report bugs or request features
- Discussions: Community discussions and Q&A
This project is licensed under the GNU Affero General Public License v3.0 - see the LICENSE file for details.
Built with β€οΈ by the teuto.net team
β Star us on GitHub β’ π Report Issues β’ π¬ Join Discussions