ingress, kubernetes, networking, web

Automatically provision TLS certificates in kubernetess with cert-manager

In the first part of Ingress & TLS in kubernetes series I have introduced self-signed certificates. The process was entirely controlled by manual actions and created certs were not accepted by the browser. This time the creation will be done automatically using cert-manager.

I will start from the place I ended in previous post, so if you want to follow along, take a look at part one.

Remove some resources

# hence we will use cert-manager to provision certificates, manually created secret will be no longer needed
$ k delete secret ingress-local-tls

Install cert-manager using Helm

$ helm repo add jetstack
"jetstack" has been added to your repositories

$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "jetstack" chart repository
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈Happy Helming!⎈

$ helm install \
  cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version v1.4.0 \
  --set installCRDs=true

$ k get po -n cert-manager
NAME                                       READY   STATUS    RESTARTS   AGE
cert-manager-5d7f97b46d-nmfgb              1/1     Running   0          24m
cert-manager-cainjector-69d885bf55-xxpzw   1/1     Running   0          24m
cert-manager-webhook-54754dcdfd-5dkgz      1/1     Running   0          24m

$ k get crd -o name

Error getting keypair for CA issuer

If you are getting error:

Error getting keypair for CA issuer: certificate is not a CA

Please take a look at this issue for further debugging. Solution below.

Add below lines to /etc/ssl/openssl.cnf

[ v3_ca ]
basicConstraints = critical,CA:TRUE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always

In the following command I will use this configuration by passing -extensions v3_ca flag to openssl command.

Create key-pair for cert-manager’s CA

# create a new key for CA
$ openssl genrsa -out ca.key 2048
Generating RSA private key, 2048 bit long modulus
e is 65537 (0x10001)

# create certificate
$ openssl req -x509 -new -nodes -key ca.key -sha256 -subj "/CN=ingress.local" -days 365 -out ca.crt -extensions v3_ca

# put newly created key-pair in kubernetes
$ k create secret tls ca-key-pair  \
--cert=ca.crt \
secret/ca-key-pair created

# create Issuer and refer to use newly created key-pair
$ cat <<EOF| k apply -f-
kind: Issuer
  name: ca-issuer
  namespace: default
    secretName: ca-key-pair

$ k get issuer
ca-issuer   True    59s

# hence we now have issuer, we can generate proper certificate for my domain ingress.local
$ cat <<EOF| k apply -f-
kind: Certificate
  name: ingress-local
  namespace: default
  secretName: ingress-local-tls
    name: ca-issuer
    kind: Issuer
  commonName: ingress.local
    - www.ingress.local
EOF created


From now, our example site ingress.local will have similar cert as in the previous post. The only difference is that when certificate expires, it will be automatically renewed by cert-manager. Hence I still used cert signed by my own CA, it is still visible to browser as untrusted:

In the third part of this series I will eventually use cert-manager with Let's encrypt -certificates will be still automatically renewed, but also trusted by the browser.