Skip to content

cert-manager

cert-manager gives kinder clusters automatic TLS certificate management. A self-signed ClusterIssuer is created during cluster setup so you can issue Certificate resources immediately — no manual cert-manager installation or issuer configuration required.

kinder installs cert-manager v1.16.3.

ResourceNamespacePurpose
cert-manager controllercert-managerWatches Certificate resources, issues certs
cert-manager-cainjectorcert-managerInjects CA bundles into webhooks and API services
cert-manager-webhookcert-managerValidates and converts cert-manager resources
selfsigned-issuer ClusterIssuercluster-scopedSelf-signed issuer ready for immediate use

Create a self-signed certificate:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: my-cert
namespace: default
spec:
secretName: my-cert-tls
issuerRef:
name: selfsigned-issuer
kind: ClusterIssuer
dnsNames:
- myapp.local

Apply it and verify:

Terminal window
kubectl apply -f certificate.yaml
kubectl get certificate my-cert

Expected output:

NAME READY SECRET AGE
my-cert True my-cert-tls 10s

The TLS secret is now available for use in Ingress, Gateway, or pod volume mounts:

Terminal window
kubectl get secret my-cert-tls -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -subject

cert-manager pairs naturally with the Envoy Gateway addon. Create a Gateway with TLS termination:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: my-gateway
annotations:
cert-manager.io/cluster-issuer: selfsigned-issuer
spec:
gatewayClassName: eg
listeners:
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- name: my-gateway-tls

After creating a cluster, confirm all three cert-manager components are running:

Terminal window
kubectl get pods -n cert-manager

Expected output:

NAME READY STATUS RESTARTS AGE
cert-manager-... 1/1 Running 0 60s
cert-manager-cainjector-... 1/1 Running 0 60s
cert-manager-webhook-... 1/1 Running 0 60s

Verify the ClusterIssuer is ready:

Terminal window
kubectl get clusterissuer selfsigned-issuer

Expected output:

NAME READY AGE
selfsigned-issuer True 60s

cert-manager is controlled by the addons.certManager field in your cluster config:

apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
addons:
certManager: true # default

See the Configuration Reference for all available addon fields.

To create a cluster without cert-manager, set certManager: false:

apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
addons:
certManager: false

A wildcard certificate covers all subdomains under a single domain. This is useful when you have multiple services (e.g., api.example.local, app.example.local) and want a single cert to cover them all.

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: wildcard-example-local
namespace: default
spec:
secretName: wildcard-example-local-tls
duration: 2160h # 90 days
renewBefore: 360h # renew 15 days before expiry
issuerRef:
name: selfsigned-issuer
kind: ClusterIssuer
dnsNames:
- "*.example.local"
- "example.local"

Apply it and verify it reaches READY: True:

Terminal window
kubectl apply -f wildcard-cert.yaml
kubectl get certificate wildcard-example-local

Expected output:

NAME READY SECRET AGE
wildcard-example-local True wildcard-example-local-tls 15s

Symptom: kubectl get certificate shows READY: False and the status does not change.

Two common causes:

(a) Webhook not ready yet

cert-manager’s webhook takes 30–60 seconds to become ready after cluster creation. If you apply a Certificate immediately after kinder create cluster, it may fail validation.

Fix: Wait 60 seconds and reapply, or check webhook readiness first:

Terminal window
kubectl get pods -n cert-manager

All three pods must be Running before applying certificates.

(b) Wrong issuer kind

The Certificate spec has kind: Issuer but selfsigned-issuer is a ClusterIssuer.

Fix: Change kind: Issuer to kind: ClusterIssuer in the issuerRef block:

issuerRef:
name: selfsigned-issuer
kind: ClusterIssuer # not Issuer

Diagnostic commands:

Terminal window
kubectl describe certificate <name>
kubectl get certificaterequest

kubectl describe certificate shows events that indicate whether the issue is with the issuer reference or a webhook timeout. kubectl get certificaterequest shows whether cert-manager created a request at all — if no request exists, the webhook likely rejected the Certificate resource.