Cert-Manager automates the provisioning of certificates within Kubernetes clusters. It provides a set of custom resources to issue certificates and attach them to services.
One of the most common use cases is securing web apps and APIs with SSL certificates from Let’s Encrypt. Here’s how to add Cert-Manager to your cluster, set up a Let’s Encrypt certificate issuer, and acquire a certificate for Pods exposed via an Ingress.
Cert-Manager is easiest to install using Helm. Helm is a Kubernetes package manager which lets you add applications to your cluster using repositories of pre-built charts. Make sure you’ve got Helm installed and setup with a connection to your Kubernetes cluster.
Begin by adding the Jetstack repository to your Helm installation. Jetstack originally developed Cert-Manager before it was donated to the CNCF.
helm repo add jetstack https://charts.jetstack.io helm repo update
Now install Cert-Manager into your cluster:
helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.5.3 --set installCRDs=true
Replace the version number shown above with the latest release shown in the Cert-Manager documentation.
The command will install Cert-Manager in a new Kubernetes namespace called
installCRDs setting will add Cert-Manager’s custom Kubernetes resources during the installation. This only works with Helm version 3.2 and newer – if you’re using an older version, you must manually add the resource definitions with Kubectl:
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.5.3/cert-manager.crds.yaml
Adding the Kubectl Plugin
Cert-Manager has a Kubectl plugin which simplifies some common management tasks. It also lets you check whether Cert-Manager is up and ready to serve requests.
Install the plugin by downloading its archive and extracting it to the correct directory:
curl -L -o kubectl-cert-manager.tar.gz https://github.com/jetstack/cert-manager/releases/latest/download/kubectl-cert_manager-linux-amd64.tar.gz tar xzf kubectl-cert-manager.tar.gz sudo mv kubectl-cert_manager /usr/local/bin
Now use the plugin to check your Cert-Manager installation is working:
kubectl cert-manager check api
You should see the following output:
The cert-manager API is ready
Now you’re ready to add an issuer to get certificates from Let’s Encrypt.
Creating a Certificate Issuer
Issuers and cluster issuers are resources which supply certificates to your cluster. The basic Cert-Manager installation created so far is incapable of issuing certificates. Adding an issuer that’s configured to use Let’s Encrypt lets you dynamically acquire new certificates for services in your cluster.
Create a YAML file in your working directory and name it
issuer.yml. Add the following content:
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-staging spec: acme: server: https://acme-staging-v02.api.letsencrypt.org/directory email: firstname.lastname@example.org privateKeySecretRef: name: letsencrypt-staging solvers: - http01: ingress: class: nginx
You must replace the email address with your own contact email. This will be included in your certificates. Let’s Encrypt may also email you at the address if it needs to send you alerts about your certificates.
We’re creating a
ClusterIssuer as these are available to all resources in your cluster, irrespective of namespace. A standard
Issuer is a namespaced resource which can only supply certificates within its own namespace.
Our issuer configuration instructs Cert-Manager to get certificates from the Let’s Encrypt staging server. It’s a good idea to use the staging environment while you’re setting up your integration to avoid hitting Let’s Encrypt’s stringent production rate limits.
kubectl to add the issuer to your cluster:
kubectl create -f issuer.yml
Getting a Certificate
Now you can use your issuer to acquire a certificate for a service exposed via an Ingress resource. Cert-Manager automatically monitors Ingress resources and creates certificates using the configuration in their
tls field. You just need to add an annotation that names the issuer or cluster issuer you want to use.
apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 1 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: containers: - name: my-app image: wordpress:latest ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: my-app ports: port: 80 --- apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: my-ingress annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt-staging spec: rules: - host: example.com http: paths: - path: / backend: serviceName: my-service servicePort: 80 tls: - hosts: - example.com
This YAML file defines a Pod, a Service, and an Ingress exposing the service. It assumes use of
nginx-ingress as the Ingress controller. The Pod runs a WordPress container which will be accessible over HTTPS at
The presence of the
cert-manager.io/cluster-issuer annotation in the Ingress resource will be detected by Cert-Manager. It’ll use the
letsencrypt-staging cluster issuer created earlier to acquire a certificate covering the hostnames defined in the Ingress’
Using Let’s Encrypt in Production
Once you’ve successfully acquired a staging certificate, you can migrate to the Let’s Encrypt production servers. Staging certificates are valid but not trusted by browsers so you must get a production replacement before putting your site live.
It’s best to add a separate cluster issuer for the production server. You can then reference the appropriate issuer in each of your Ingress resources, depending on whether they’re production-ready.
Copy the issuer configuration shown above and change the
name fields to
letsencrypt-production. Next, replace the server URL with the value shown below:
Create the new issuer in your cluster:
kubectl create -f issuer-production.yml
Update your Ingress resource to request a production certificate by changing the value of the
cert-manager.io/cluster-issuer annotation to
letsencrypt-production (or the name you assigned to your own production issuer). Use
kubectl to apply the change:
kubectl apply -f my-ingress.yaml
You should now have fully functioning HTTPS enabled for your Ingress resource. Cert-Manager will automatically manage your certificates and renew them before they expire.
Cert-Manager releases usually support in-place upgrades with Helm:
helm repo update helm upgrade --version <new version> cert-manager jetstack/cert-manager
Certificates remain available during upgrades but the renewal process will be halted.
Although upgrades are now normally straightforward, you should always review the release notes to identify potential changes you need to make. This is particularly important if you’re upgrading Kubernetes or moving through several Cert-Manager versions. If you’re still using an older Kubernetes release, you might be on an obsolete Cert-Manager version that requires significant manual intervention to bring up to date.
Let’s Encrypt is easily added to a Kubernetes cluster using Cert-Manager. You need to install Cert-Manager with Helm, create an issuer that uses the Let’s Encrypt API, then reference that issuer in your Ingress resources.
You can supply Cert-Manager with your own configuration for more advanced use cases. You can specify a certificate lifetime (use the
cert-manager.io/duration Ingress annotation), manually declare the certificate’s common name (
cert-manager.io/common-name), and use DNS challenges instead of HTTP. The latter option can be useful in specific scenarios, such as when you want to acquire a wildcard certificate.
Straightforward usage to protect web apps and APIs should work as-is using the resources shown above. HTTP verification works by manipulating the Ingress controller to provide a temporary
.well-known URL that Let’s Encrypt can access. If your domain provides the correct value at that URL, Let’s Encrypt trusts you’re in control and issues the certificate.