KubeLB integrates with external-dns and cert-manager to provide automatic DNS record management and TLS certificate provisioning for your load balancers and routes. This guide covers setup and configuration.
Overview
KubeLB supports DNS automation through:
external-dns : Automatically creates DNS records for your load balancers
cert-manager : Provisions and manages TLS certificates
Tenant DNS Settings : Per-tenant configuration for DNS and certificates
Architecture
DNS and certificate management works as follows:
Service/Route Creation : You create a LoadBalancer service or HTTP route
DNS Annotations : KubeLB adds external-dns annotations to resources
DNS Record Creation : external-dns watches for annotations and creates DNS records
Certificate Request : cert-manager provisions TLS certificates
Certificate Storage : Certificates are stored as Kubernetes secrets
external-dns and cert-manager must be installed and configured in the management cluster.
DNS Configuration
Tenant DNS Settings
Configure DNS behavior for a tenant:
apiVersion : kubelb.k8c.io/v1alpha1
kind : Tenant
metadata :
name : tenant-cluster-1
spec :
dns :
# Base domain for wildcard DNS records
wildcardDomain : "apps.example.com"
# Allow explicit hostnames
allowExplicitHostnames : true
# Add external-dns annotations
useDNSAnnotations : true
# Add cert-manager annotations
useCertificateAnnotations : true
Wildcard Domain
When wildcardDomain is set, KubeLB automatically generates hostnames:
apiVersion : v1
kind : Service
metadata :
name : api-service
namespace : default
spec :
type : LoadBalancer
selector :
app : api
ports :
- port : 80
targetPort : 8080
With wildcardDomain: "apps.example.com", this creates:
Hostname: api-service.default.apps.example.com
DNS A record pointing to the load balancer IP
Explicit Hostnames
Use explicit hostnames with LoadBalancer services:
apiVersion : kubelb.k8c.io/v1alpha1
kind : LoadBalancer
metadata :
name : my-app-lb
namespace : tenant-cluster-1
spec :
hostname : "api.example.com" # Explicit hostname
endpoints :
- addressesReference :
kind : Addresses
name : default
ports :
- port : 80
protocol : TCP
Explicit hostnames only work if allowExplicitHostnames: true in the Tenant configuration.
external-dns Integration
Setup
Install external-dns
Install external-dns in the management cluster: helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/
helm install external-dns external-dns/external-dns \\
--namespace external-dns \\
--create-namespace \\
--set provider=aws \\
--set txtOwnerId=kubelb-cluster
See external-dns documentation for provider-specific configuration.
Configure DNS Provider
Configure credentials for your DNS provider (AWS Route53, Google Cloud DNS, etc.). For AWS Route53: # Create secret with AWS credentials
apiVersion : v1
kind : Secret
metadata :
name : external-dns-aws
namespace : external-dns
type : Opaque
data :
aws-access-key-id : <base64-encoded-access-key>
aws-secret-access-key : <base64-encoded-secret-key>
Enable DNS Annotations in Tenant
apiVersion : kubelb.k8c.io/v1alpha1
kind : Tenant
metadata :
name : tenant-cluster-1
spec :
dns :
wildcardDomain : "apps.example.com"
useDNSAnnotations : true
DNS Annotations
KubeLB propagates external-dns annotations:
Ingress
Gateway
HTTPRoute
apiVersion : networking.k8s.io/v1
kind : Ingress
metadata :
name : my-ingress
namespace : default
annotations :
external-dns.alpha.kubernetes.io/hostname : myapp.example.com
external-dns.alpha.kubernetes.io/ttl : "300"
spec :
ingressClassName : kubelb
rules :
- host : myapp.example.com
http :
paths :
- path : /
pathType : Prefix
backend :
service :
name : my-service
port :
number : 80
apiVersion : gateway.networking.k8s.io/v1
kind : Gateway
metadata :
name : my-gateway
namespace : default
annotations :
external-dns.alpha.kubernetes.io/hostname : gateway.example.com
spec :
gatewayClassName : kubelb
listeners :
- name : http
protocol : HTTP
port : 80
apiVersion : gateway.networking.k8s.io/v1
kind : HTTPRoute
metadata :
name : my-route
namespace : default
annotations :
external-dns.alpha.kubernetes.io/hostname : api.example.com
external-dns.alpha.kubernetes.io/ttl : "600"
spec :
parentRefs :
- name : my-gateway
hostnames :
- "api.example.com"
rules :
- backendRefs :
- name : api-service
port : 8080
Verifying DNS Records
Check that DNS records are created:
# Check external-dns logs
kubectl logs -n external-dns -l app.kubernetes.io/name=external-dns
# Query DNS
dig myapp.example.com
nslookup myapp.example.com
# Check for TXT records (ownership records)
dig TXT myapp.example.com
cert-manager Integration
Setup
Install cert-manager
Install cert-manager in the management cluster: kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.0/cert-manager.yaml
Create ClusterIssuer
Create a ClusterIssuer for Let’s Encrypt: apiVersion : cert-manager.io/v1
kind : ClusterIssuer
metadata :
name : letsencrypt-prod
spec :
acme :
server : https://acme-v02.api.letsencrypt.org/directory
email : [email protected]
privateKeySecretRef :
name : letsencrypt-prod-key
solvers :
# HTTP-01 solver
- http01 :
ingress :
class : kubelb
# DNS-01 solver for wildcard certs
- dns01 :
route53 :
region : us-east-1
accessKeyID : <aws-access-key-id>
secretAccessKeySecretRef :
name : route53-credentials
key : secret-access-key
Configure Tenant
apiVersion : kubelb.k8c.io/v1alpha1
kind : Tenant
metadata :
name : tenant-cluster-1
spec :
certificates :
defaultClusterIssuer : letsencrypt-prod
dns :
useCertificateAnnotations : true
TLS with Ingress
Automatic Certificate
Manual Certificate
Let cert-manager automatically provision a certificate: apiVersion : networking.k8s.io/v1
kind : Ingress
metadata :
name : tls-ingress
namespace : default
annotations :
cert-manager.io/cluster-issuer : letsencrypt-prod
spec :
ingressClassName : kubelb
tls :
- hosts :
- secure.example.com
secretName : secure-tls # cert-manager will create this
rules :
- host : secure.example.com
http :
paths :
- path : /
pathType : Prefix
backend :
service :
name : secure-service
port :
number : 80
cert-manager will:
Create a Certificate resource
Request certificate from Let’s Encrypt
Store certificate in secure-tls secret
Create a Certificate resource manually: apiVersion : cert-manager.io/v1
kind : Certificate
metadata :
name : secure-cert
namespace : default
spec :
secretName : secure-tls
issuerRef :
name : letsencrypt-prod
kind : ClusterIssuer
dnsNames :
- secure.example.com
- www.secure.example.com
---
apiVersion : networking.k8s.io/v1
kind : Ingress
metadata :
name : tls-ingress
namespace : default
spec :
ingressClassName : kubelb
tls :
- hosts :
- secure.example.com
- www.secure.example.com
secretName : secure-tls
rules :
- host : secure.example.com
http :
paths :
- path : /
pathType : Prefix
backend :
service :
name : secure-service
port :
number : 80
TLS with Gateway API
Gateway TLS
Certificate Resource
apiVersion : gateway.networking.k8s.io/v1
kind : Gateway
metadata :
name : tls-gateway
namespace : default
annotations :
cert-manager.io/cluster-issuer : letsencrypt-prod
spec :
gatewayClassName : kubelb
listeners :
- name : https
protocol : HTTPS
port : 443
hostname : "*.example.com"
tls :
mode : Terminate
certificateRefs :
- name : wildcard-tls # cert-manager will provision
allowedRoutes :
namespaces :
from : All
apiVersion : cert-manager.io/v1
kind : Certificate
metadata :
name : wildcard-cert
namespace : default
spec :
secretName : wildcard-tls
issuerRef :
name : letsencrypt-prod
kind : ClusterIssuer
dnsNames :
- "*.example.com"
- example.com
---
apiVersion : gateway.networking.k8s.io/v1
kind : Gateway
metadata :
name : tls-gateway
namespace : default
spec :
gatewayClassName : kubelb
listeners :
- name : https
protocol : HTTPS
port : 443
tls :
mode : Terminate
certificateRefs :
- name : wildcard-tls
Wildcard Certificates
Use DNS-01 challenge for wildcard certificates:
apiVersion : cert-manager.io/v1
kind : Certificate
metadata :
name : wildcard-cert
namespace : default
spec :
secretName : wildcard-tls
issuerRef :
name : letsencrypt-prod
kind : ClusterIssuer
dnsNames :
- "*.apps.example.com"
- "apps.example.com"
Ensure your ClusterIssuer has DNS-01 solver configured.
Certificate Renewal
cert-manager automatically renews certificates:
# Check certificate status
kubectl get certificate
# Get certificate details
kubectl describe certificate secure-cert
# Check cert-manager logs
kubectl logs -n cert-manager -l app=cert-manager
Certificates are renewed 30 days before expiration by default.
Annotation Propagation
Control which annotations are propagated to load balancers:
apiVersion : kubelb.k8c.io/v1alpha1
kind : Tenant
metadata :
name : tenant-cluster-1
spec :
propagateAllAnnotations : false
propagatedAnnotations :
# External DNS annotations
external-dns.alpha.kubernetes.io/hostname : ""
external-dns.alpha.kubernetes.io/ttl : ""
external-dns.alpha.kubernetes.io/target : ""
# cert-manager annotations
cert-manager.io/cluster-issuer : ""
cert-manager.io/issuer : ""
cert-manager.io/common-name : ""
# Custom annotations
my-annotation.example.com/key : "allowed-value"
Empty value ("") allows any value for that annotation key.
Complete Example
Here’s a complete example with DNS and TLS:
Configure Tenant
apiVersion : kubelb.k8c.io/v1alpha1
kind : Tenant
metadata :
name : tenant-cluster-1
spec :
dns :
wildcardDomain : "apps.example.com"
useDNSAnnotations : true
useCertificateAnnotations : true
certificates :
defaultClusterIssuer : letsencrypt-prod
propagatedAnnotations :
external-dns.alpha.kubernetes.io/hostname : ""
cert-manager.io/cluster-issuer : ""
Create Ingress
apiVersion : networking.k8s.io/v1
kind : Ingress
metadata :
name : my-app
namespace : default
annotations :
cert-manager.io/cluster-issuer : letsencrypt-prod
external-dns.alpha.kubernetes.io/hostname : myapp.example.com
spec :
ingressClassName : kubelb
tls :
- hosts :
- myapp.example.com
secretName : myapp-tls
rules :
- host : myapp.example.com
http :
paths :
- path : /
pathType : Prefix
backend :
service :
name : my-app-service
port :
number : 80
Verify DNS and Certificate
# Wait for DNS propagation
dig myapp.example.com
# Check certificate
kubectl get certificate myapp-tls
# Test HTTPS
curl https://myapp.example.com
Troubleshooting
Check external-dns logs: kubectl logs -n external-dns -l app.kubernetes.io/name=external-dns
Verify annotations: kubectl get ingress my-app -o yaml
Look for external-dns.alpha.kubernetes.io/hostname annotation. Check propagated annotations:
Ensure the annotation is allowed in Tenant propagatedAnnotations.
Check certificate status: kubectl get certificate
kubectl describe certificate myapp-tls
Check certificate request: kubectl get certificaterequest
kubectl describe certificaterequest < request-nam e >
Check cert-manager logs: kubectl logs -n cert-manager -l app=cert-manager
Common issues:
DNS not propagated yet (for DNS-01 challenge)
Ingress not accessible (for HTTP-01 challenge)
Rate limits from Let’s Encrypt
Verify certificate secret exists: kubectl get secret myapp-tls
Check certificate validity: kubectl get secret myapp-tls -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -noout
Test TLS connection: curl -v https://myapp.example.com
openssl s_client -connect myapp.example.com:443 -servername myapp.example.com
Best Practices
Use Staging Issuer First
Test with Let’s Encrypt staging to avoid rate limits:
apiVersion : cert-manager.io/v1
kind : ClusterIssuer
metadata :
name : letsencrypt-staging
spec :
acme :
server : https://acme-staging-v02.api.letsencrypt.org/directory
email : [email protected]
privateKeySecretRef :
name : letsencrypt-staging-key
solvers :
- http01 :
ingress :
class : kubelb
Wildcard Certificates
Use wildcard certificates for multiple subdomains:
apiVersion : cert-manager.io/v1
kind : Certificate
metadata :
name : wildcard-cert
namespace : default
spec :
secretName : wildcard-tls
issuerRef :
name : letsencrypt-prod
kind : ClusterIssuer
dnsNames :
- "*.example.com"
- "example.com"
Monitor Certificate Expiration
Set up alerts for certificate expiration:
# Certificates expiring in less than 7 days
certmanager_certificate_expiration_timestamp_seconds - time() < 7 * 24 * 3600
Next Steps