cert-manager is a powerful and extensible X.509 certificate controller for Kubernetes. It can manage certificates in the SKS environment and in combination with our cert-manager-webhook it integrates with Exoscale DNS for issuing certificates using ACME DNS01 challenge.

In this short article we will show you how to add a cert-manager to an SKS cluster and configure it to generate a Let’s Encrypt certificate for a domain managed by Exoscale DNS service.


Prerequisites:

Installing cert-manager and cert-manager-webhook

The easiest way to add cert-manager to an SKS cluster is using static manifest as described in the official cert-manager installation page:

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.10.0/cert-manager.yaml

By default cert-manager will be in its own namespace inside a cluster:

$ kubectl get pods -n cert-manager
NAME                                     READY   STATUS    RESTARTS   AGE
cert-manager-646dddd544-sxz24            1/1     Running   0          22s
cert-manager-cainjector-8676c4b7-q7s9w   1/1     Running   0          22s
cert-manager-webhook-557fb758cf-989db    1/1     Running   0          22s

cert-manager-webhook is installed using Helm and a Helm Chart in the official cert-manager webhook repository:

git clone https://github.com/exoscale/cert-manager-webhook-exoscale.git
cd cert-manager-webhook-exoscale
helm install exoscale-webhook ./deploy/exoscale-webhook

Now we can see cert-manager-webhook running in the default namespace:

$ kubectl get pods
NAME                                            READY   STATUS    RESTARTS        AGE
cert-manager-webhook-exoscale-d7dccb674-9czqw   1/1     Running   0               31s

Issuing a certificate for a domain

With cert-manager and cert-manager-webhook in place, we can proceed to create a new certificate for our domain. In this example we will generate a certificate for example.com.

cert-manager-webhook requires Exoscale API credentials to manage a DNS record used in the ACME DNS01 challenge. We can generate a restricted access key using Exoscale CLI:

 $ exo iam access-key create \
    --operation list-dns-domains \
    --operation list-dns-domain-records \
    --operation  get-dns-domain-record \
    --operation get-operation \
    --operation create-dns-domain-record \
    --operation delete-dns-domain-record \
    cert-manager-webhook-key
┼────────────────┼─────────────────────────────────────────────┼
│ IAM ACCESS KEY │                                             │
┼────────────────┼─────────────────────────────────────────────┼
│ Name           │ cert-manager-webhook-key                    │
│ Type           │ restricted                                  │
│ API Key        │ EXOabcdefghijklmnopqrstuvwx                 │
│ API Secret     │ ABCDEFGIJKLMNOPQRSTUVWXYZabcdefgijklmnopqrs │
│ Operations     │ list-dns-domain-records                     │
│                │ get-dns-domain-record                       │
│                │ get-operation                               │
│                │ list-dns-domains                            │
│                │ create-dns-domain-record                    │
│                │ delete-dns-domain-record                    │
┼────────────────┼─────────────────────────────────────────────┼

The recommended way to provide API credentials to cert-manager-webhook is using the Kubernetes secret resource. We can create a secret.yaml file with the following content:

apiVersion: v1
stringData:
  EXOSCALE_API_KEY: EXOabcdefghijklmnopqrstuvwx
  EXOSCALE_API_SECRET: ABCDEFGIJKLMNOPQRSTUVWXYZabcdefgijklmnopqrs
kind: Secret
metadata:
  name: exoscale-secret
type: Opaque

Adding the resource is as simple as running:

kubectl create -f secret.yaml

Now we can reference our secret when creating an Issuer resource (issuer.yaml):

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: exoscale-issuer
spec:
  acme:
    email: my-user@example.com
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: exoscale-private-key-secret
    solvers:
    - dns01:
        webhook:
          groupName: acme.exoscale.com
          solverName: exoscale
          config:
            apiKeyRef:
              key: EXOSCALE_API_KEY
              name: exoscale-secret
            apiSecretRef:
              key: EXOSCALE_API_SECRET
              name: exoscale-secret

Issuers are Kubernetes resources representing certificate authorities (CAs), that are able to generate signed certificates by honoring certificate signing requests. We can add the resource as before:

kubectl create -f issuer.yaml

The final piece of the puzzle is the Certificate resource. A Certificate resource specifies fields that are used to generate certificate signing requests, including domain name and which issuer they want to obtain the certificate from. Our new resource (certificate.yaml) will look like this:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-com
spec:
  dnsNames:
  - example.com
  issuerRef:
    name: exoscale-issuer
  secretName: example-com-tls

And to add a resource:

kubectl create -f certificate.yaml

It may take a minute or two but eventually we will see our new certificate in the ready state:

$ kubectl get certificate example-com
NAME          READY   SECRET            AGE
example-com   True    example-com-tls   0m52s

That’s it, now we have a valid certificate in our cluster!


Head over to cert-manager documentation for further use cases like Securing Ingress Resources.