Cert-manager is a Kubernetes tool that automates the management of TLS certificates in a Kubernetes cluster. It can issue certificates from various sources, such as Let’s Encrypt or self-signed certificates.
Cert-manager automatically renews these certificates once two thirds of the certificate’s validity period has elapsed.
In this guide, we’ll show you how to install and configure Cert-manager to issue Let’s Encrypt certificates in your Kubernetes cluster.
Before you follow this guide, install:
- The Helm package manager
- Traefik to act as the Gateway Controller (replacing the old Nginx Ingress Controller).
Installing Cert-manager
Step 1
Add the Jetstack repository. This is the only official source for cert-manager Helm charts. Then, with the second command, update your repositories so you can use the Jetstack repository.
helm repo add jetstack https://charts.jetstack.io
helm repo update
Step 2
Install Cert-manager with the command:
helm install \
cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.12.0 \
--set installCRDs=true- You’re free to use a different namespace name than cert-manager, but this one is easy to recognise.
- Replace v1.12.0 with the latest stable version, as shown here on GitHub.
- The installCRDs option is required, but alternatively you can comment out the installCRDs option and install the CRDs separately using the command below (in short, a CRD is code that extends the Kubernetes API with custom resources that aren’t part of the core Kubernetes API):
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.0/cert-manager.crds.yamlYou’ll now see output like the example below to confirm that the installation was successful:
NAME: cert-manager LAST DEPLOYED: Tue Jun 13 13:21:23 2023 NAMESPACE: cert-manager STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: cert-manager v1.11.0 has been deployed successfully! In order to begin issuing certificates, you will need to set up a ClusterIssuer or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer). More information on the different types of issuers and how to configure them can be found in our documentation: https://cert-manager.io/docs/configuration/ For information on how to configure cert-manager to automatically provision Certificates for Ingress resources, take a look at the `ingress-shim` documentation: https://cert-manager.io/docs/usage/ingress/
You can check the status of the Pods and Services created for Cert-manager with the following commands, respectively:
kubectl get pods -n cert-manager
kubectl get svc -n cert-manager
Creating an (Cluster)Issuer
To use Cert-manager, you’ll need a ClusterIssuer or an Issuer. A ClusterIssuer defines a certificate issuer (for example Let’s Encrypt) that can be used to generate TLS certificates for your entire Kubernetes cluster. An Issuer can only do this for a specific namespace.
Step 1
Create a .yaml file, for example letsencrypt-issuer.yaml:
nano letsencrypt-issuer.yamlThere are two options for generating SSL certificates: HTTP-01 and DNS-01. For wildcard certificates (e.g. for *.voorbeeld.nl), use the DNS-01 option. We support this option via our API, and we’ll explain DNS-01 on that basis. If you choose a different provider, make sure it supports this functionality and that the domains you use are registered with that provider in the account you use for this guide.
Are you using an external domain? Then use the HTTP-01 option, but bear in mind that you won’t be able to generate wildcard certificates.
DNS-01
Step 1
Cert-manager supports a number of DNS providers such as Cloudflare, but unfortunately not TransIP. To use DNS-01 anyway, Cert-manager supports webhooks, which you can think of as a kind of plugin. In this case, you’ll use a webhook so Cert-manager can use the TransIP API.
Install the webhook as follows (replace cert-manager with your namespace name if needed):
helm repo add cert-manager-webhook-transip https://demeester.dev/cert-manager-webhook-transip
helm install --namespace cert-manager cert-manager-webhook-transip cert-manager-webhook-transip/cert-manager-webhook-transip
Step 2
Create a directory where you’ll store your TransIP API key, for example:
mkdir transipNext, create a file in the directory you just created containing a private key from your TransIP API account, for example:
cat << EOF > transip/transip.key
-----BEGIN PRIVATE KEY-----
MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDKoaYJtbVnJw58
PYGH8WIJ7ZjWd2lke0IbMV+dNGs=
-----END PRIVATE KEY-----
EOFThis example only includes a small fragment of a private key. Your private key will be much longer.
Step 3
Create a Secret based on your API private key that Cert-manager can use to communicate with the TransIP API. If necessary, replace the following values:
- -n cert-manager: Use the name of the namespace you created in step 2 of the previous section.
- transip/transip.key: Change this to the directory and file name you created in the previous step.
kubectl create -n cert-manager secret generic transip-key --from-file transip/transip.key
Step 4
Set the file contents to the following:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-issuer-dns01
spec:
acme:
email: <YOUR_EMAIL_ADDRESS>
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-issuer-dns01
solvers:
- dns01:
webhook:
groupName: acme.transip.nl
solverName: transip
config:
accountName: <YOUR_TRANSIP_ACCOUNT_NAME>
ttl: 300
privateKeySecretRef:
name: transip-secret
key: privateKey
Replace <YOUR_EMAIL_ADDRESS> with your own email address and <YOUR_TRANSIP_ACCOUNT_NAME> with the name of your TransIP account. Finally, save your changes and close the file (Ctrl + X > Y > Enter).
HTTP-01
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-issuer
spec:
acme:
email: <YOUR_EMAIL_ADDRESS>
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-issuer
solvers:
- http01:
ingress:
class: traefik
Replace <YOUR_EMAIL_ADDRESS> with your own email address. Finally, save your changes and close the file (Ctrl + X > Y > Enter).
Step 2
Apply the configuration from the .yaml file to your cluster:
kubectl apply -f letsencrypt-issuer.yaml You’ll now see a confirmation that the configuration was applied successfully:
clusterissuer.cert-manager.io/letsencrypt-issuer created
Note: When you want to generate a certificate (see the next section), you’ll create an Ingress resource that must use exactly the value shown above, i.e. clusterissuer.cert-manager.io/letsencrypt-issuer
Using Cert-manager
Cert-manager is now ready to use. Rather than an Nginx Ingress Controller, in this article we’ll assume Traefik as the Gateway Controller (Gateway API). Using Cert-manager then consists of two parts:
- You have Cert-manager issue a TLS certificate (as a Kubernetes Secret).
- You attach that Secret to your
Gatewaylistener viatls.certificateRefs.
It’s recommended that you deploy the application (Deployment/Service) first, before you create the certificate and the Gateway/HTTPRoute resources.
Step 1
Make sure your (sub)domain points to Traefik’s public address (the LoadBalancer). This is the IP address or the *.haip.transip.net hostname you’ll see with kubectl get svc -n traefik. Without this DNS record, Let’s Encrypt (with HTTP-01) can’t validate your domain.
Step 2
Create a Certificate resource in the same namespace as your Gateway (in this example demo-gateway). Cert-manager will then create a TLS Secret (e.g. demo-gateway-tls) that you’ll use in the Gateway later.
nano demo-certificate.yamlFor example, give the file the following contents (adjust the domain/issuer/namespace as required):
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: demo-cert
namespace: demo-gateway
spec:
secretName: demo-gateway-tls
issuerRef:
name: letsencrypt-issuer
kind: ClusterIssuer
dnsNames:
- demo.voorbeeld.nl
Step 3
Apply the resource to your Kubernetes cluster with the command:
kubectl apply -f demo-certificate.yaml
Step 4
Check whether the certificate has been issued. Under READY you should eventually see True, and under SECRET the Secret you specified in spec.secretName.
kubectl get certificate -n demo-gateway
kubectl describe certificate demo-cert -n demo-gatewayDo you see READY False? Then also check the underlying challenge/order resources to find the cause:
kubectl get challenge,order,certificaterequest -n demo-gateway
Step 5
Now link the issued TLS Secret to your Gateway. In the HTTPS listener, reference the same Secret (demo-gateway-tls) via tls.certificateRefs. Note: Traefik’s Helm chart often uses entryPoints on 8000/8443 (externally still 80/443); make sure the listener ports match your Traefik entryPoints.
Create a file/resource, for example named demo-gateway.yaml, with the following contents (adjust hostnames/ports/namespace to match your setup):
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: demo-gateway
namespace: demo-gateway
spec:
gatewayClassName: traefik
listeners:
- name: web
protocol: HTTP
port: 8000
hostname: demo.voorbeeld.nl
allowedRoutes:
namespaces:
from: Same
- name: websecure
protocol: HTTPS
port: 8443
hostname: demo.voorbeeld.nl
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: demo-gateway-tls
allowedRoutes:
namespaces:
from: Same
Step 6
Reapply the configuration using a kubectl apply -f command:
kubectl apply -f demo-gateway.yaml
Step 7
To automatically redirect HTTP to HTTPS without duplicate rules or redirect loops, create two separate HTTPRoute resources:
- A route on the HTTP listener (
sectionName: web) that only performs a redirect tohttps. - A route on the HTTPS listener (
sectionName: websecure) that forwards traffic to your backend Service.
For example, first create the HTTP->HTTPS redirect route in a file/resource named demo-httproute-redirect.yaml:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: demo-route-redirect
namespace: demo-gateway
spec:
parentRefs:
- name: demo-gateway
sectionName: web
hostnames:
- demo.supporttest.nl
rules:
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301Then create the HTTPS route that points to your application in a file/resource named demo-httproute.yaml:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: demo-route
namespace: demo-gateway
spec:
parentRefs:
- name: demo-gateway
sectionName: websecure
hostnames:
- demo.supporttest.nl
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: demo-app
port: 80
Step 8
Apply both routes and check the status:
kubectl apply -f demo-httproute-redirect.yaml
kubectl apply -f demo-httproute.yaml
kubectl describe gateway demo-gateway -n demo-gateway
kubectl describe httproute demo-route-redirect -n demo-gateway
kubectl describe httproute demo-route -n demo-gatewayThat’s it! HTTP traffic to http://demo.supporttest.nl is now automatically redirected to https://demo.supporttest.nl, and HTTPS traffic is routed to your backend Service.