SSL with Let’s Encrypt#

Let’s Encrypt is a service that automatically issues certificates if you can prove you control a website. Certificate Manager is a Kubernetes project that automates the process of getting a certificate from Let’s Encrypt when a new host name appears in your DNS records. Certificates are tied to particular DNS names and IP addresses, so you must have External DNS working. Certificates can only be applied to Ingress resources so you must have an Ingress controller working too.

Before You Begin

There are prerequisites that must be complete for you to do this lab:

  1. You must have an Ingress controller working

  2. You must have External DNS working

Introduction#

Let’s Encrypt validates that you own a domain by asking you to create custom DNS records. So we will reuse the service accounts from the Install External DNS lab. After that we can install Cert Manager.

Add Role Bindings#

Use the existing role account:

$ project=$(gcloud config get-value core/project)
$ sa_name="Kubernetes external-dns"
$ sa_email=$(gcloud iam service-accounts list --format='value(email)' \
    --filter="displayName:$sa_name")
$ gcloud iam service-accounts add-iam-policy-binding "$sa_email" \
    --member="serviceAccount:${project}.svc.id.goog[default/cert-manager]" \
    --role=roles/iam.workloadIdentityUser

Create Values for the Cert Manager Chart#

Put this YAML fragment into a file called deployment/values-cert-manager.yaml:

Warning

Update the file to contain your project ID.

installCRDs: true

prometheus:
  enabled: false 

serviceAccount:
  create: true 
  name: cert-manager
  annotations:     
    iam.gke.io/gcp-service-account: sa-edns@YOUR-PROJECT-ID.iam.gserviceaccount.com

global:
  leaderElection:
    namespace: cert-manager

resources:
  requests:
    memory: "512Mi"
    cpu: "250m"
    ephemeral-storage: "10Mi"
  limits:
    memory: "512Mi"
    cpu: "250m"
    ephemeral-storage: "10Mi"

webhook:
  resources:
    requests:
      memory: "512Mi"
      cpu: "250m"
      ephemeral-storage: "10Mi"
    limits:
      memory: "512Mi"
      cpu: "250m"
      ephemeral-storage: "10Mi"

cainjector:
  resources:
    requests:
      memory: "512Mi"
      cpu: "250m"
      ephemeral-storage: "10Mi"
    limits:
      memory: "512Mi"
      cpu: "250m"
      ephemeral-storage: "10Mi"

startupapicheck:
  resources:
    requests:
      memory: "512Mi"
      cpu: "250m"
      ephemeral-storage: "10Mi"
    limits:
      memory: "512Mi"
      cpu: "250m"
      ephemeral-storage: "10Mi"

Install Cert Manager#

Now use Helm to install Cert Manager:

$ helm repo add jetstack https://charts.jetstack.io
$ helm repo update
$ helm install cert-manager jetstack/cert-manager --version v1.7.1 --values deployment/values-cert-manager.yaml

Create Let’s Encrypt Configuration#

Add the following contents to deployment/cluster-issuer.yaml:

Warning

Update the file to contain your project ID and email address.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt
spec:
  acme:
    email: you@you.com
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-account-key
    solvers:
    - dns01:
        cloudDNS:
          project: YOUR-PROJECT-ID

Apply the issuer resource with:

$ kubectl apply -f deployment/cluster-issuer.yaml

Monitor the Issuer#

Use kubectl get all to get the name of the cert-manager pod. Use the name to watch the logs as you update the Ingress resource:

$ kubectl logs -f pod/cert-manager-7b68dcc5d-96pr8

Update the Ingress Resource#

Update your Ingress resource to have some annotations and a tls section like this:

Warning

Update the file to contain your DNS name.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: cis-92-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    cert-manager.io/cluster-issuer: letsencrypt
spec:
  tls: 
  - hosts:
    - mysite.mydomain.com
    secretName: apps-cert-secret
  rules:
  - host: "mysite.domain.com"
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: mysite
            port:
              number: 80

Apply the resource:

$ kubectl apply -f deployment/ingress.yaml

It can take several minutes for the ingress controller to settle. Check the logs of both Cert Manager and External DNS to make sure there’s no errors.