This gist will guide you through the setup of a wildcard Let's encrypt TLS certificate.
Let’s encrypt is one of a new kind of Certificate Authority. You can get a TLS certificate from them for your website free of charge and without any manual overhead. These certificates are trusted in most browsers that are out there and will show up as valid. Instead of sending Mails or even paper around you can call an API and prove your domain ownership with simple challenges. Basically you call the API with a hostname or domain name you need a TLS certificate for and you get back a challenge string that you need to put in a well known location on your http host or as a txt record in your dns system.
You can find many clients that manage the process and keep your TLS certificates up to date. In the area of kubernetes I can highly recommend cert-manager which is the successor of kube-lego. It’s quite easy to deploy via the helm chart.
If you have a bigger installation which is more dynamic - hostnames come and go - you will hit rate limits pretty soon which will block your account from getting new TLS certificates for quite some time.
If you for example want every developer to have a dedicated API endpoint in the cluster to test a micro service app you can create an isolated environment. So something like marco.dev.company.de
and feature-two.dev.company.de
should be deployable.
If you are using the simple http proof you get the system up and running but you can’t scale the installation.
The cert-manager has the ability to use the dns proof with Azure-DNS and will create the TXT record and maintain the certificates. You pretty much don’t have to worry about the details.
First make sure to install the cert-manager helm chart in your cluster. You can follow along the guide on the cert-manager website.
Now it’s time to configure a ClusterIssuer that can be used to create certificates. As mentioned you can find the config for azure DNS here. You need to feed the API with the client id and client secret of a ServicePrinicipal that has the privilege to update DNS entries.
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
commonName: '*.dev.company.de'
dnsNames:
- "*.dev.company.de"
acme:
server: "https://acme-v02.api.letsencrypt.org/directory"
email: [email protected]
privateKeySecretRef:
name: letsencrypt-prod
dns01:
providers:
- name: azure-dns
domains:
- '*.dev.company.de'
azuredns:
clientID: "###CLIENT_ID###"
clientSecretSecretRef:
key: client-secret
name: azuredns-config
hostedZoneName: "dev.company.de"
resourceGroupName: "infrastructure"
subscriptionID: "###SUBSCRIPTION_ID###"
tenantID: "###TENANT_ID###"
Don’t forget to provide the client secret.
kubectl -n kube-system create secret generic azuredns-config --from-literal=client-secret="$CLIENT_SECRET"
Now you have configured how new tls certificates can be retrieved.
Now you can define a Certificate API object that describes the validity of the desired format. The format will be retrieved using the letsencrypt-prod ClusterIssuer defined by the issuerRef. The certificate will be placed in a secret named wildcard-domain-tls-secret that can be wired up to an ingress resource.
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
name: wildcard-domain
namespace: default
spec:
secretName: wildcard-domain-tls-secret
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
commonName: '*.dev.company.de'
dnsNames:
- '*.dev.company.de'
acme:
config:
- dns01:
provider: azure-dns
domains:
- '*.dev.company.de'
And the final part is to use the wildcard certificate.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ template "my-app.fullname" . }}-ingress
labels:
type: infrastructure
app: {{ template "my-app.fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
rules:
- host: {{ .Values.ingress.frontend.host }}
http:
paths:
- path: /
backend:
serviceName: {{ template "my-app.fullname" $ }}-frontend
servicePort: 80
{{ if .Values.ingress.tls.enabled }}
tls:
- hosts:
- {{ .Values.ingress.frontend.host }}
{{ if .Values.ingress.tls.letsEncrypt }}
secretName: wildcard-domain-tls-secret
{{ else }}
secretName: {{ template "my-app.fullname" $ }}-ingress-tls-frontend-secret
{{ end }}
{{ end }}
You see that I simply reference the certificate in the TLS section of the manifest. I needed to distinguish between a Let’s Encrypt environment and a self provisioned secret so I made the whole part switchable using variables.
Now you create new hosts in your environment without delays and any rate limits.