Cert Manager is the de-facto tool for managing certificates in Kubernetes. It’s a great tool and has been an essential part of the Kubernetes ecosystem.
When migrating from Ingress to Gateway API, cert-manager requires configuration changes and your existing ClusterIssuers may need updates.
The key difference is enabling Gateway API support in cert-manager’s controller configuration.
Standard cert-manager installation for Ingress:
# values.yaml
crds:
enabled: true
Enable Gateway API support:
# values.yaml
crds:
enabled: true
config:
apiVersion: controller.config.cert-manager.io/v1alpha1
kind: ControllerConfiguration
enableGatewayAPI: true
HTTP01 challenge solvers need updates to reference Gateway resources instead of Ingress.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-production
spec:
acme:
email: user@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-account-key
solvers:
- http01:
ingress:
ingressClassName: nginx
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-production
spec:
acme:
email: user@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-account-key
solvers:
- http01:
gatewayHTTPRoute:
parentRefs:
- kind: Gateway
name: default
namespace: default
sectionName: http
DNS01 challenge configuration remains unchanged between Ingress and Gateway API:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-production-dns
spec:
acme:
email: user@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-dns-account-key
solvers:
- dns01:
route53:
region: eu-central-1
accessKeyIDSecretRef:
name: route53-credentials
key: access-key-id
secretAccessKeySecretRef:
name: route53-credentials
key: secret-access-key
Cert-manager annotations work similarly on both Ingress and Gateway resources. The only difference is that the annotations are applied to the Gateway resource instead of the Ingress resource.
| Ingress Annotation | Gateway Annotation | Notes |
|---|---|---|
cert-manager.io/cluster-issuer | cert-manager.io/cluster-issuer | Same annotation, apply to Gateway |
cert-manager.io/issuer | cert-manager.io/issuer | Same annotation, apply to Gateway |
cert-manager.io/common-name | cert-manager.io/common-name | Same annotation |
cert-manager.io/duration | cert-manager.io/duration | Same annotation |
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example
annotations:
cert-manager.io/cluster-issuer: letsencrypt-production
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com
secretName: example-tls
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend
port:
number: 80
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: example
annotations:
cert-manager.io/cluster-issuer: letsencrypt-production
spec:
gatewayClassName: kubelb
listeners:
- name: https
protocol: HTTPS
port: 443
hostname: example.com
tls:
mode: Terminate
certificateRefs:
- name: example-tls
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: example
spec:
parentRefs:
- name: example
hostnames:
- example.com
rules:
- backendRefs:
- name: backend
port: 80
Be aware of these limitations when migrating cert-manager to Gateway API.
Gateway API does not support wildcard certificates with HTTP01 challenge. You must use DNS01 challenge for wildcards:
# This will NOT work with Gateway API + HTTP01
listeners:
- hostname: "*.example.com" # Wildcard requires DNS01
HTTP01 solver requires explicit Gateway reference with parentRefs. Unlike Ingress where you just specify ingressClassName, Gateway API needs:
With Ingress, cert-manager creates and manages the Certificate resource automatically. With Gateway API, the same applies but the Certificate is associated with the Gateway, not individual routes.
If you have multiple Gateways, you need separate ClusterIssuers or use DNS01 challenge which doesn’t require Gateway references.
gatewayHTTPRoute instead of ingress