Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save marcopaga/1b6d045d85099cbf32456443a6e3cdf7 to your computer and use it in GitHub Desktop.
Save marcopaga/1b6d045d85099cbf32456443a6e3cdf7 to your computer and use it in GitHub Desktop.
Let's encrypt wildcard TLS certificates for Azure DNS using cert-manager on AKS (Azure Kubernetes Service)

This gist will guide you through the setup of a wildcard Let's encrypt TLS certificate.

Let's encrypt

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.

The little helper for Kubernetes: Cert-Manager

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.

DNS01 Challenge with AzureDNS for a Wildcard Certificate

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.

Installation and Configuration

Cert-Manager via helm

First make sure to install the cert-manager helm chart in your cluster. You can follow along the guide on the cert-manager website.

Setup the Cluster-Issuer

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: your-admin-account@company.de
	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.

Setup the wildcard certificate

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'

Use the wildcard certificate

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.

Enjoy

Now you create new hosts in your environment without delays and any rate limits.

@librannk
Copy link

Hi can you show a demo of this using istio gateway too ... instead of ingress

@Morgma
Copy link

Morgma commented Sep 20, 2019

@librannk Did you happen to find a good example of this? I've found plenty of standard Ingress also, but very view people using a proper Gateway with wildcard. Closest I've found to a working model is this (no wildcard, but AKS + Istio Gateway Ingress + LetsEncrypt).

@marcopaga
Copy link
Author

@librannk @Morgma The config I created here is unrelated to the ingress or gateway config. Just setup your istio gateway and point it to the tls secret which is provided by the cert-manager.

Btw: We moved from using cert-manager to the Traefik controller managing the Let's encrypt certificates for us.

@librannk
Copy link

@Morgma: link shared by you was similar to something I did and is working fine, although auto-rotate of certificate is something which isn't working for me
@marcopage: Any benefits of using Traefic ?

@joelharkes
Copy link

Sweet, nice piece of documentation. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment