Introduction

In this post we will configure cert-manager on Kubernetes in order to manage your traffic using HTTPS (SSL/TLS) certificates with cert-manager and Let’s Encrypt. At Octopus, we’ve seen firsthand how important security is in the world of cloud services. Our team’s deep expertise in Kubernetes and open-source technologies ensures that we’re adept at guiding clients through securing their traffic. Cert-manager is one of these tools that we recommend. Even in air-gapped disconnected environments.

In order to better understand the procedure let’s explain a few concepts related to the operator:

ClusterIssuer – A custom resource (extending k8s api) that assist in certificate issuance on a cluster-wide scope. Instead of dealing with individual issuers per namespace, a ClusterIssuer allows you to set a single point of certificate management that can serve certificates to applications across different namespaces

Issuer – Same as ClusterIssuer only limited to a namespace.

CA – represent a Certificate Authority (CA) that can issue certificates. By creating a CA object, we essentially allow cert-manager to act as its own Certificate Authority. This enables us to issue certificates based on a CA private key, which is useful for production air-gapped/disconnected, internal or testing purposes.

ACME – An issuer Automated Certificate Management Environment (ACME) Certificate Authority server. Can be configured using a specific email.

Procedure

cert-manager provides Helm charts as a first-class method of installation on both Kubernetes and OpenShift.

Be sure never to embed cert-manager as a sub-chart of other Helm charts
cert-manager manages non-namespaced resources in your cluster and care must be taken to ensure that it is installed exactly once.

Add the helm repo

Use the following to add the helm chart repo and update the helm repositories on the machine

$ helm repo add jetstack https://charts.jetstack.io
$ helm repo update

Install cert-manager

Use the following to install the cert-manager operator:

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

Generate a local CA

In our example we don’t have a CA from our organization, we can use the following commands to create a CA:

# generate an rsa key
openssl genrsa -out k8stests-root-ca-key.pem 2048

# generate root certificate
openssl req -x509 -new -nodes -key k8stests-root-ca-key.pem \
  -days 3650 -sha256 -out k8stests-root-ca.pem -subj "/CN=k8stests-ca"

Create the secret to hold that CA

The following command will load the CA key and cert to the kubernetes etcd into a secret.

kubectl create secret tls -n cert-manager root-ca \
  --cert=k8stests-root-ca.pem \
  --key=k8stests-root-ca-key.pem

Cluster-issuer

Let’s create the ClusterIssuer object. The ClusterIssuer will sign our required certificates using cert-manger automatically. This object is the base for our certificates.

kubectl apply -n cert-manager -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: ca-issuer
spec:
  ca:
    secretName: root-ca
EOF

Configuration wise, this is the main configuration we need to do. Now let’s see how we can configure a certificate based on this CA.

Issue a certificate

Using Ingress Operator you can now use the cluster-issuer in order to issue certificates.

For example, add to your ingress application the following lines:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: root-ca
.
.
.

NOTE: the name of our CA is root-ca it might be different on your cluster.

Configuring Let’s Encrypt

Assuming your cluster is connected to the internet, we can use Let’s Encrypt and their CA to have a allowed and known SSL/TLS certificate on every computer in the world.

Let’s Encrypt is a widely-used, free certificate authority that provides SSL/TLS certificates for securing web traffic. Its automated processes make obtaining and deploying certificates incredibly easy. With the cert-manager it’s even easier.

Let’s Encrypt uses the ACME protocol (Automatic Certificate Management Environment) to automate the process of obtaining and renewing SSL/TLS certificates. ACME is the communication protocol that enables a server to request certificates from Let’s Encrypt and prove its control over the domain

Staging Issuer

Let’s configure the staging issuer. The organization provides access to the staging signing server for us to do tests.

04_letsencrypt_staging.yaml

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    # You must replace this email address with your own.
    # Let's Encrypt will use this to contact you about expiring
    # certificates, and issues related to your account.
    email: letsencrypt@k8s.co.il
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      # Secret resource that will be used to store the account's private key.
      name: letsencrypt-staging-key
    # Add a single challenge solver, HTTP01 using nginx
    solvers:
    - http01:
        ingress:
          class: nginx

Create it:

$ k create -f 04_letsencrypt_staging.yaml

Production Issuer

Now, let’s create the Let’s Encrypt signing production system

05_letsencrypt_production.yaml

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-production
spec:
  acme:
    # You must replace this email address with your own.
    # Let's Encrypt will use this to contact you about expiring
    # certificates, and issues related to your account.
    email: letsencrypt@k8s.co.il
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      # Secret resource that will be used to store the account's private key.
      name: letsencrypt-production-key
    # Add a single challenge solver, HTTP01 using nginx
    solvers:
    - http01:
        ingress:
          class: nginx

Let’s create the LetsEncrypt Production ClusterIssuer:

$ k create -f 05_letsencrypt_staging.yaml

You should now have 3 cluster issuers:

# k get clusterissuer
NAME                     READY   AGE
ca-issuer                True    99d
letsencrypt-production   True    32d
letsencrypt-staging      True    32d

With these cluster issuers, you can add a secure connection with HTTPS configuration derived from Nginx Ingress Operator.

An example for such a usage can be seen in our post of How to deploy Harbor registry on Kubernetes :

Adding the following line to the values of the ingress of your application will create a certificate for you.

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

Here’s the output of the above certificate generated with Let’s Encrypt’s ISRG Root X1 CA and R3 Intermediate CA.

certificates issued by cert-manager

Summary

Certificates are vital for securing data and building trust with users. Using cert-manager in Kubernetes for this, they ensure safe communication dynamically. I hope this will help you integrate and manage certificates with cert-manager in Kubernetes. Upgrading your security.

Enjoy!