Use cert-manager for control plane certificates

Uses: Kong Mesh
TL;DR

Create a self-signed ClusterIssuer, a CA Certificate, a CA-backed Issuer, and a control plane Certificate in the kong-mesh-system namespace, then set controlPlane.tls.general.secretName in your Helm values to point to the generated secret.

Prerequisites

You will need Helm, a package manager for Kubernetes.

This guide requires a running Kubernetes cluster. If you already have a Kubernetes cluster running, you can skip this step. It can be a cluster running locally, like Docker, or in a public cloud like AWS EKS, GCP GKE, etc.

For example, if you are using minikube:

minikube start -p mesh-zone

Install cert-manager in your cluster to issue and rotate certificates automatically:

helm repo add jetstack https://charts.jetstack.io
helm repo update
helm upgrade --install \
  cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --set crds.enabled=true
kubectl wait -n cert-manager --for=condition=ready pod --all --timeout=90s

By default, Kong Mesh generates its own self-signed control plane certificates at startup. Using cert-manager lets you manage the full certificate lifecycle, issuance, rotation, and expiration, outside of the control plane itself. This guide walks you through creating the required cert-manager resources and configuring Kong Mesh to use them.

Create the Kong Mesh namespace

The cert-manager resources in the following steps are scoped to the kong-mesh-system namespace, which Kong Mesh uses at install time:

kubectl create namespace kong-mesh-system

Create a self-signed ClusterIssuer

A ClusterIssuer is a cluster-scoped resource that cert-manager uses to sign certificates. Create a self-signed one as the root of your certificate chain:

echo "apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}" | kubectl apply -f -

Create the CA certificate

Use the selfsigned-issuer to create a CA certificate in the kong-mesh-system namespace. This certificate acts as the root CA that signs the control plane certificate:

echo "apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: kong-mesh-selfsigned-ca
  namespace: kong-mesh-system
spec:
  isCA: true
  commonName: kong-mesh-selfsigned-ca
  secretName: root-secret
  privateKey:
    algorithm: ECDSA
    size: 256
  issuerRef:
    name: selfsigned-issuer
    kind: ClusterIssuer
    group: cert-manager.io" | kubectl apply -f -

cert-manager stores the CA certificate and key in a secret named root-secret in the kong-mesh-system namespace.

Create the CA-backed Issuer

Create a namespace-scoped Issuer in kong-mesh-system that uses the CA secret to sign certificates:

echo "apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: kong-mesh-issuer
  namespace: kong-mesh-system
spec:
  ca:
    secretName: root-secret" | kubectl apply -f -

Create the control plane certificate

  1. Create a Certificate resource that cert-manager uses to issue and renew the control plane TLS certificate. The dnsNames must include all the DNS names that data planes use to reach the control plane:

    echo "apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: control-plane-cert
      namespace: kong-mesh-system
    spec:
      secretName: control-plane-cert
      duration: 2160h
      renewBefore: 360h
      isCA: false
      privateKey:
        algorithm: RSA
        encoding: PKCS1
        size: 2048
      usages:
        - server auth
      dnsNames:
        - kong-mesh-control-plane.kong-mesh-system.svc
        - kong-mesh-control-plane
        - kong-mesh-control-plane.kong-mesh-system
        - kong-mesh-control-plane.kong-mesh-system.svc.local
      issuerRef:
        name: kong-mesh-issuer
        kind: Issuer" | kubectl apply -f -
  2. Wait for the certificate to be issued:

    kubectl wait -n kong-mesh-system --for=condition=ready certificate/control-plane-cert --timeout=60s

Install Kong Mesh with the cert-manager certificate

Install Kong Mesh and point the control plane TLS configuration at the secret cert-manager created:

helm repo add kong-mesh https://kong.github.io/kong-mesh-charts
helm repo update
helm upgrade --install \
  --namespace kong-mesh-system \
  kong-mesh kong-mesh/kong-mesh \
  --set controlPlane.tls.general.secretName=control-plane-cert
kubectl wait -n kong-mesh-system --for=condition=ready pod --selector=app=kong-mesh-control-plane --timeout=90s

If Kong Mesh is already installed, run helm upgrade instead of helm install with the same --set flag.

Validate

Verify that the control plane is running and using the cert-manager-issued certificate.

  1. Confirm the control plane pod is healthy:

    kubectl get pods -n kong-mesh-system

    The kong-mesh-control-plane pod should show Running in the STATUS column.

  2. Inspect the certificate that cert-manager stored in the secret:

    kubectl get secret -n kong-mesh-system control-plane-cert \
      -o jsonpath='{.data.tls\.crt}' | base64 -d | \
      openssl x509 -noout -subject -issuer -dates

    The output should show kong-mesh-selfsigned-ca as the issuer and an expiration date 90 days from issuance. For example:

    subject=
    issuer=CN=kong-mesh-selfsigned-ca
    notBefore=Jun 17 09:50:10 2026 GMT
    notAfter=Sep 15 09:50:10 2026 GMT

    The subject is empty because cert-manager sets identity via SANs rather than a common name.

  3. Confirm cert-manager will renew the certificate automatically:

    kubectl get certificate -n kong-mesh-system control-plane-cert

    The READY column should show True.

Cleanup

To clean up your environment, remove the Docker containers, network, temporary directory, and the control plane configuration. Run the following command:

kubectl config delete-context mesh-zone

Help us make these docs great!

Kong Developer docs are open source. If you find these useful and want to make them better, contribute today!