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
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.