Auto TLS with cert-manager and Traefik

Auto TLS with cert-manager and Traefik

Achieve high availability

·

4 min read

Cover image taken from github.com/ashleymcnamara/gophers

On my previous post, Traefik in actions. The Cloud Native Edge Router, we have learnt how to setup Traefik and introduce some feature. It was using default ACME for https setup. On recent twitter discussion, I learnt that we can use cert-manager as alternative to the default ACME.

Also, if want to achieve High Availability (HA) on Traefik open source version, can't rely on default ACME.

If you require LetsEncrypt with HA in a kubernetes environment, we recommend using Traefik Enterprise where distributed LetsEncrypt is a supported feature.

If you are wanting to continue to run Traefik Community Edition, LetsEncrypt HA can be achieved by using a Certificate Controller such as Cert-Manager.

from CRD docs

In this post, we will try out cert-manager for that.

Installation

I will walk through the demo on Google Cloud (GKE and Google DNS) with terraform, but the concept can be applied to other hosted Kubernetes or distribution

The source code can be found at cncf-demo

If you wish to follow along, make sure you have Google Cloud project created, and download service account with appropriate IAM roles assigned, to be used with terraform.

Also, create another service account for with DNS Administrator role assigned for DNS validation purposes.

git clone https://github.com/WLun001/cncf-demo
cd terraform/gke-traefik-cert-manager
terraform init
# it will provision GKE cluster
# install traefik and cert-manager with helm
# and create kubernetes secret for Google Cloud DNS
terraform apply

optionally you can create terraform.tfvars to store variables for terraform

$ cat terraform.tfvars
credentials_file = "google-cloud-service-account.json"
google_dns_sa_file = "dns-service-account.json"
project = "your-project-id"

Verify the installation, alternatively you can use console provided by cloud providers or Kubernetes dashbaord

$ kubectl get deploy,svc -n traefik
NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/traefik   1/1     1            1           24h

NAME              TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)                      AGE
service/traefik   LoadBalancer   10.3.243.228    SOME_EXTERNAL_IP   80:30619/TCP,443:30267/TCP   24h

$ kubectl get deploy,svc -n cert-manager
NAME                                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/cert-manager              1/1     1            1           24h
deployment.apps/cert-manager-cainjector   1/1     1            1           24h
deployment.apps/cert-manager-webhook      1/1     1            1           24h

NAME                           TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/cert-manager           ClusterIP   10.3.243.121   <none>        9402/TCP   24h
service/cert-manager-webhook   ClusterIP   10.3.247.6     <none>        443/TCP    24h

You should be able to access Traefik on the external IP on port 80, add the external IP to your DNS nameserver.

Create sample apps

Let's create some sample apps, to be routed by Traefik

cd kubernetes
kubectl apply -f whoami.yaml -f zone-printer.yaml

Create ClusterIssuer and Certificate

The configuration below uses DNS Validation, which support wildcard certificates. Checkout the docs for HTTP Validation. For supported DNS validation, can view from supported dns01 providers docs

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: cert-wildcard-issuer
  namespace: default
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: youremail@email.com
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      # Secret resource used to store the account's private key.
      name: cert-wildcard-issuer
    solvers:
      - selector: { }
        dns01:
          cloudDNS:
            project: YOUR_PROJECT_ID
            serviceAccountSecretRef:
              name: google-dns-sa
              key: key.json

---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-cert
  namespace: default
spec:
  secretName: wildcard-example-com-tls
  issuerRef:
    kind: ClusterIssuer
    name: cert-wildcard-issuer
  dnsNames:
    - "*.example.com"
kubectl apply -f cert-manager.yaml

Check the certificate creation progress

kubectl get certificates
kubectl describe certificates wildcard-cert

It should be ready in a few minutes. If you stuck at Issuing state, might need to troubleshoot it.

Once it is done, verify the tls secret is created

$ kubectl get secret
NAME                         TYPE                                  DATA   AGE
wildcard-example-com-tls   kubernetes.io/tls                     2      22h

Create ingressRoute

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: myingressroute-secure
  namespace: default

spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`traefik.example.com`) && PathPrefix(`/`)
      kind: Rule
      services:
        - name: hello-world-service
          port: 80
    - match: Host(`traefik.example.com`) && PathPrefix(`/whoami`)
      kind: Rule
      services:
        - name: whoami
          port: 80
    - match: Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
      kind: Rule
      services:
        - name: api@internal
          kind: TraefikService
      middlewares:
        - name: basic-auth
    - match: Host(`api.example.com`) && PathPrefix(`/`)
      kind: Rule
      services:
        - name: whoami
          port: 80
  tls:
    secretName: wildcard-example-com-tls # -> the tls secret is applied here
kubectl apply -f ingress-route-cert-manager.yaml

If you need to see the error log , if there is any, can check with kubectl. If any error with ingress route, it will be visible here.

kubectl logs -f deployment/traefik -n traefik

Verify the certificate

Screenshot 2020-11-25 at 10.30.23 PM.png

Clean up

All cloud resources cost money, make sure you clean up after experiment.

cd terraform/gke-traefik-cert-manager
terraform destroy

That's all for today, if you have any feedback, feel free to comment below.

The source code can be found at cncf-demo.

Reference

Did you find this article valuable?

Support Wei Lun by becoming a sponsor. Any amount is appreciated!