Jeff
Jeff Cloud Systems Architect
1 min read / TL;DR

Using Certmanager with Cloudflare and Kubernetes

Using Certmanager with Cloudflare and Kubernetes

How to configure certmanager for DNS challenges with Cloudflare and Kubernetes


What is Certmanager

Certmanager is a native Kubernetes cluster certificate manager. This article aims to outline the process of using Certmanager to manage SSL certificate creation and renewals via letsencrypt. Prior to certificate issuance, letsencrypt requires a challenge to verify ownership of a domain. In this article, we will configure Certmanager and letsencrypt to use a DNS-01 challenge against Cloudflare hosted DNS.

Requirements

  • A working Kubernetes Cluster
  • Kubectl connected to your cluster
  • A valid domain name that you own
  • DNS for said damain hosted by Cloudflare

Verify kubectl is connected to your cluster

kubectl get nodes

You should see your Kubernetes nodes printed. If not, please configure your kubectl to connect to your cluster

Cloudflare API Key

Let’s Encrypt offers several domain verification methods. The simplest solutions is their HTTP-01 challenge, which uses a file hosted on your website as verification. This method is not always useful, as our websites may not be publicly accessible. In our case, we are going to make use of the DNS-01 challenge. When using the DNS-01 challenge, Let’s Encrypt will require the creation of a TXT record with a random code. Certmanager will automate the creation and deletion of these TXT challenge DNS recrods. To do so, we will need give our certmanager install access to manage our DNS records. In our case, we’re using Cloudflare, which makes use of API keys.

Obtaining your API Key

Certmanager can now use a Zone Specific API Key

  1. Log into your Cloudflare Dashboard
  2. Click on your Account Icon (top right of page)
  3. Click "My Profile"
  4. Click on "API Tokens"
  5. Click "Create Token"
  6. Create a Token with the following permissions
    1. Token Name: cert-manager
    2. Zone - Zone - Read
    3. Zone - DNS - Edit

Install Certmanager

Pre-reqs

Create a namespace, install CRDs and Certmanager

Updated on March 17th, 2020. Update the version tag below to the newest release of cert-manager

CERT_MANAGER_VERSION=v0.14.0
kubectl create namespace cert-manager
kubectl label namespace cert-manager certmanager.k8s.io/disable-validation=true
# Kubernetes 1.15+
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/$CERT_MANAGER_VERSION/cert-manager.yaml

#Kubernetes <1.15
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/$CERT_MANAGER_VERSION/cert-manager-legacy.yaml

Verify that Cert Manager has Installed

kubectl get po -n cert-manager

NAME                                       READY   STATUS    RESTARTS   AGE
cert-manager-5d8d74bb4d-7n2qq              1/1     Running   0          15h
cert-manager-cainjector-5db54b6b45-5hrwt   1/1     Running   0          15h
cert-manager-webhook-7cd5d4fdd7-95smt      1/1     Running   0          15h

Cloudflare API Secret

You need your Cloudflare API Key

This will create a new Kuberentes secret with your Cloudflare API Key for Certmanager to reference.

API_KEY=$(echo YOUR-API-KEY-HERE | base64 -)
cat <<EOF | kubectl apply -f -
---
apiVersion: v1
kind: Secret
metadata:
  name: cloudflare-api-key
  namespace: cert-manager
type: Opaque
data:
  api-key: ${API_KEY}
EOF

Create a Staging Issuer

Since Let's Encrypt imposes a limit of 50 certificates per domain per week, we should do all of our testing against their Staging envrionment. Only use the Production envrionment once you have finished your testing.

EMAIL_ADDRESS="[email protected]"
cat <<EOF | kubectl apply -f -
---
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: ${EMAIL_ADDRESS}
    privateKeySecretRef:
      name: letsencrypt-staging
    dns01:
      providers:
      - name: cf-dns
        cloudflare:
          email: ${EMAIL_ADDRESS}
          apiTokenSecretRef:
            name: cloudflare-api-key
            key: api-key
EOF

Create a Production Issuer

This will be used after your testing is complete

EMAIL_ADDRESS="[email protected]"
cat <<EOF | kubectl apply -f -
---
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: ${EMAIL_ADDRESS}
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - dns01:
        cloudflare:
          email: ${EMAIL_ADDRESS}
          apiTokenSecretRef:
            name: cloudflare-api-key
            key: api-key
EOF

Add Ingress Annotations

Now that Certmanager is configure, we need to add annotations to our ingress documents to make use of it. Add the following annotations to your ingress documents

  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    kubernetes.io/tls-acme: "true"
    kubernetes.io/ssl-redirect: "true"

Then add the following to the spec section of your ingress document. Replace domain.tld with your domain name. Add additional entries here for subdomains or alias domains. You will also provide a secretName name here, this is where certmanager will store your private key and certificate

  tls:
  - hosts:
    - domain.tld
    secretName: domain-tld-tls