cert-manager is a Kubernetes add-on to automate the management and issuance of TLS certificates from various issuing sources (e.g. Let's Encrypt).
In order to get a certificate from Let's Encrypt, it is necessary to prove the control of the domain names in that certificate through a challenge, as defined by the ACME standard. Two different types of challenges are available [1],[2]:
- HTTP-01 challenge: requires to put a specific value in a file on the web server at a specific path;
- DNS-01 challenge: requires to put a specific value in a TXT record under that domain name.
In the following, both types of challenges are configured and made available. Indeed, the former is easier to use but it requires a public IP and port 80 to be open and reachable. The latter, on the other hand, does not suffer from this limitation and allows to issue wildcard certificates, but it can be used only for the DNS names under our control.
- Ensure that
/etc/bind/named.conf
contains the following:... include "/etc/bind/named.conf.keys"; include "/etc/bind/named.conf.local"; ...
- Create the new TSIG keys to authenticate cert-manager record updates (one for each zone):
# tsig-keygen -a hmac-sha512 crownlabs-certmanager | tee --append /etc/bind/named.conf.keys # tsig-keygen -a hmac-sha512 crownlabs-internal-certmanager | tee --append /etc/bind/named.conf.keys
- Edit
/etc/bind/named.conf.local
, and authorize the keys to insert TXT records for the zones of interest:zone "crownlabs.polito.it" { ... update-policy { grant crownlabs-certmanager zonesub txt; }; }; ... zone "internal.crownlabs.polito.it" { ... update-policy { grant crownlabs-internal-certmanager zonesub txt; }; };
- Reload the
bind9
configuration:# rndc reload
- Install the
CustomResourceDefinitions
andcert-manager
itself:$ kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v0.16.1/cert-manager.yaml
- Create the
ServiceMonitor
resource, to make Prometheus aware of the metrics exposed bycert-manager
(Grafana dashboard with ID 11001):$ kubectl create -f cert-mananger-service-monitor.yaml
- Create the
ClusterIssuer
resources, which operate as an interface to request the issuance of digital certificates. In the following, two different resources are created, respectively for development (letsencrypt-staging
) and production (letsencrypt-production
). Indeed, the latter is associated with stricter rate limits [3]:Note: in case a different DNS server is used, it is necessary to edit the$ kubectl create -f lets-encrypt-issuer-staging.yaml $ kubectl create -f lets-encrypt-issuer-production.yaml
yaml
files with the correct configuration. Additionally, it is also possible to configure the email address that will be associated with the digital certificates issued by Let's Encrypt. - Create the new
Secret
resources storing the TSIG keys previously generated to interact with the DNS server:$ kubectl -n cert-manager create secret generic crownlabs-certmanager-tsig --from-literal=crownlabs-certmanager-tsig-key=<TSIG-key> $ kubectl -n cert-manager create secret generic crownlabs-internal-certmanager-tsig --from-literal=crownlabs-internal-certmanager-tsig-key=<TSIG-key>
- Verify that the
ClusterIssuer
resources are in Ready state:$ kubectl describe ClusterIssuer -n cert-manager
A common use-case for cert-manager is requesting TLS signed certificates to secure Ingress
resources. This operation can be performed automatically adding an ad-hoc annotation to the Ingress
resource pointing to the ClusterIssuer
resource of interest:
...
annotations:
cert-manager.io/cluster-issuer: letsencrypt-production
...
A valid certificate associated with the Ingress
host is automatically generated and stored within the secret pointed by the tls.secretName
field of the Ingress
resource.
A Certificate
resource can be created to manually request the issuance of a digital certificate for a specific host name belonging to the DNS zone under control. certificate-example.yaml provides an example configuration to request a certificate; please refer to the official documentation [4] for more information.
By default, cert-manager has been configured to prove the control of the domain names to be certified using HTTP-01 challenges. To use DNS-01 challenges, instead, it is necessary to add the ad-hoc label to the Ingress
or Certificate
resource:
labels:
use-dns01-solver: "true"
In different scenarios, it may happen to have different Ingress
resources in different namespaces which refer to the same domain (with different paths). Unfortunately, annotating all these ingresses with the cert-manager.io/cluster-issuer
annotation soon leads to hitting the Let's Encrypt rate limits. Hence, it is necessary to introduce some mechanism to synchronize the secret generated between multiple namespaces. One of the projects currently providing a solution to this problem is kubed.
Kubed can be easily installed with helm [5].
$ helm repo add appscode https://charts.appscode.com/stable/
$ helm repo update
$ helm search repo appscode/kubed --version v0.12.0
$ kubectl create namespace kubed
$ helm install kubed appscode/kubed \
--version v0.12.0 \
--namespace kubed \
--set enableAnalytics=false \
--set config.clusterName="crownlabs"
Once kubed is installed, secrets can be duplicated in multiple namespaces, and kept synchronized, by adding the ad-hoc annotation [6]:
...
annotations:
kubed.appscode.com/sync: "namespace-label=value"
...
Warning, the kubed annotation needs to applied to the Secret
created by the certificate and not to the Certificate
itself.