Cert-Manager

Let’s Encrypt certificates

SSL certificates can be automatically fetched and setup for applications deployed on the Kubernetes cluster via cert-manager. We deploy a letsencrypt-prod ClusterIssuer by default, which uses dns01 validation via Route 53.

To use this ClusterIssuer and get a certificate for your application, you simply need to add the following annotation to the Ingress object:

cert-manager.io/cluster-issuer: letsencrypt-prod

You’ll also need to add a tls section in the spec of the Ingress object, like the following:

tls:
  - secretName: foo-example-com-tls
    hosts:
      - foo.example.com

With the hosts array of the tls section you’re telling cert-manager which domains need to be in the certificate, and in which Secret it should store the private key.

You can also define your own Issuers and/or ClusterIssuers.

You can get a list of all issued certificates:

$ kubectl get certificates --all-namespaces
NAMESPACE        NAME                                 CREATED AT
infrastructure   cert-manager-webhook-ca              9m
infrastructure   cert-manager-webhook-webhook-tls     9m
infrastructure   foo-staging-cert                     2m
infrastructure   kubesignin-alertmanager-lego-tls     5m
infrastructure   kubesignin-dashboard-lego-tls        5m
infrastructure   kubesignin-grafana-lego-tls          5m
infrastructure   kubesignin-kibana-lego-tls           5m
infrastructure   kubesignin-kubesignin-app-lego-tls   5m
infrastructure   kubesignin-prometheus-lego-tls       5m
infrastructure   wild-staging-cert                    37s

cert-manager can also issue certificates for delegated domains. If the domain name you want to use for your ingress is hosted in some external DNS servers where cert-manager doesn’t have access, you can delegate the ACME validation domain to the cluster DNS zone by creating a CNAME record in the external DNS servers. You can read more about this feature in the official cert-manager documentation and in the example below.

Warning

Cert Manager has a limit of 60 parallel certificate Challenges that can be processed at the same time. If this limit has been reached, and it’s filled with unprocessable Challenges (eg. due to DNS misconfiguration / not propagated), then these will block any further certificate issuance. You can see how many Challenges are currently being processed by running kubectl get challenges -A (check / count which are pending).

Examples

Below are some simple examples on how to issue certificates as usually done on the Ingress.

There are way more possibilities than described in the examples, which you can find in the official documentation.

Get a LetsEncrypt certificate using defaults (dns01)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  name: foo
  namespace: default
spec:
  ingressClassName: traefik
  rules:
    - host: foo.staging.skyscrape.rs
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: foo
                port:
                  name: http
  tls:
    - secretName: foo-staging-tls
      hosts:
        - foo.staging.skyscrape.rs

Get a LetsEncrypt certificate using the http01 challenge

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  labels:
    use-http-solver: "true"
  name: bar
  namespace: default
spec:
  ingressClassName: traefik
  rules:
    - host: bar.staging.skyscrape.rs
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: bar
                port:
                  name: http
  tls:
    - secretName: bar-staging-tls
      hosts:
        - bar.staging.skyscrape.rs

Get a LetsEncrypt wildcard certificate using the dns01 challenge

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  name: lorem
  namespace: default
spec:
  ingressClassName: traefik
  rules:
    - host: lorem.staging.skyscrape.rs
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: lorem
                port:
                  name: http
  tls:
    - secretName: wildcard-staging-skyscrape-rs-tls
      hosts:
        - '*.staging.skyscrape.rs'
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  name: ipsum
  namespace: default
spec:
  ingressClassName: traefik
  rules:
    - host: ipsum.staging.skyscrape.rs
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: ipsum
                port:
                  name: http
  tls:
    - secretName: wildcard-staging-skyscrape-rs-tls
      hosts:
        - '*.staging.skyscrape.rs'

You could also issue a Certificate first to re-use that later in your Ingresses:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-staging-skyscrape-rs
  namespace: default
spec:
  secretName: wildcard-staging-skyscrape-rs-tls
  issuerRef:
    kind: ClusterIssuer
    name: letsencrypt-prod
  dnsNames:
    - 'skyscrape.rs'
    - '*.skyscrape.rs'

Note

While it is possible to generate multiple wildcard certificates via a different secretName, it is advised / more efficient to reuse the same Secret for all ingresses using the wildcard.

Note

A Secret is scoped within a single Namespace, which means if you want to use a wildcard certificate in another Namespace cert-manager will request and validate a new certificate from LetsEncrypt (unless you replicate the Secrets).

Get a certificate for a delegated domain name

Let’s say you want a certificate for the domain api.example.com but cert-manager doesn’t have access to the root DNS zone for example.com. In this situation you can create a CNAME record in the example.com DNS zone like this:

_acme-challenge.api.example.com   IN   CNAME   _acme-challenge.api.production.eks.example.org.

*Considering production.eks.example.org is the FQDN of your K8s cluster.

After this, you create your Ingress as described in the examples above, and cert-manager will follow the CNAME record to create the certificate validation record in the cluster DNS zone, where it does have access.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  name: api
  namespace: default
spec:
  ingressClassName: traefik
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api
                port:
                  name: http
  tls:
    - secretName: api-example-com-tls
      hosts:
        - api.example.com
Last updated on