Why are there at least two different ways to confirm that you own and control a domain? Well, because the situations can also be different.
In the case of HTTP-01 the validation is done in a pretty dumb way: ACME client puts a special file on your server at http://<YOUR_DOMAIN>/.well-known/acme-challenge/<TOKEN>, and Let's Encrypt tries to GET it. Usually it works, but I spend quite a lot of time struggling with this method — it turns out my configuration blocks port 80 (thus GETting is not possible), and you cannot issue the wildcard certificate (*.telescope.ac) anyway if you use HTTP-01.
That's why there is a DNS-01 challenge. In this case, the validation is done via a TXT record under the domain name. You can read more about different details of the validation process here: https://letsencrypt.org/docs/challenge-types
99% of all the guides focus on HTTP-01 — mostly because this validation method works in almost all cases. However, I used DNS-01, and I want to focus more on this method. It's also worth saying that my guide uses DigitalOcean, and cert-manager supports its API by default.
It means that you won't need to create TXT records manually if you use DigitalOcean — just give cert-manager an access the DO API, and it will do all these things automatically.
Of course, cert-manager also supports other DNS providers like AzureDNS, Cloudflare, Google CloudDNS, etc. However, don't worry if your provider is not supported — in this case you will just need to create all the TXT records manually.
apiVersion: certmanager.k8s.io/v1alpha1
kind: Issuer
metadata:
name: letsencrypt-telescope-dns
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: <EMAIL>
privateKeySecretRef:
name: letsencrypt-telescope-dns
solvers:
- dns01:
cnameStrategy: Follow
digitalocean:
tokenSecretRef:
name: telescope-digitalocean-dns
key: access-token
(based on https://docs.cert-manager.io/en/latest/tasks/issuers/setup-acme/dns01/digitalocean.html).
Save it in issuer.yaml, and apply like that:
> kubectl apply -f issuer.yaml
This configuration defines an Issuer that contacts Let’s Encrypt in order to issue certificates. It uses an access token from DigitalOcean that we're now going to define.
apiVersion: v1
kind: Secret
metadata:
name: telescope-digitalocean-dns
data:
access-token: <YOUR TOKEN IN BASE64>
> kubectl apply -f secret.yaml
This is how the definition of a DigitalOcean token looks like. But how can I get one?
Just go to https://cloud.digitalocean.com/account/api/tokens and generate a new personal access token. DigitalOcean will ask for a name, and then print you the new token. You have to transform it to base64 and then paste to the snippet above.
This is how it can be done on Mac/Linux:
> echo -n '<TOKEN>' | base64
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
name: mydomain-com-certificate
spec:
secretName: telescope-ac-tls
issuerRef:
name: letsencrypt-mydomain-dns
commonName: telescope.ac
dnsNames:
- mydomain.com
- "*.mydomain.com"
> kubectl apply -f certificate.yaml
Ok, we're done with all the cert-manager definitions. We've also told it how to generate certificates and what mechanism to use to validate domains. The last step is to create an Ingress that will use the Issuer we defined above.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: mydomain-ingress
annotations:
kubernetes.io/ingress.class: nginx
certmanager.k8s.io/issuer: letsencrypt-mydomain-dns
spec:
tls:
- hosts:
- mydomain.com
- subdomain.mydomain.com
...
secretName: mydomain-ingress-tls
rules:
- host: mydomain.ac
http:
paths:
- backend:
serviceName: mydomain-backend-service
servicePort: 80
- host: subdomain.mydomain.com
http:
paths:
- backend:
serviceName: mydomain-backend-service
servicePort: 80
...
Cert-manager should have already created some orders and challenges (kubectl get orders). Unfortunately, all of them will fail because you have to create A records to your newly created LoadBalancer first.
First, get its IP address:
kubectl get services nginx-ingress-controller
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-ingress-controller LoadBalancer x.x.x.x x.x.x.x 80:31830/TCP,443:31137/TCP 65m
What you need is EXTERNAL-IP. You have to wait if kubectl shows <pending> there.
After you got the IP address, the important step is to create A records for all your domains and subdomains. Just got to the domain management page of DigitalOcean and add them there.
Now you have to wait for some time (issuance takes some, but it shouldn't be longer than 3-5 minutes). After that, you will be able to access both your domain and all the subdomains. And, of course, you will see the issuance of new certificates if you change and apply (kubectl apply -f <filename>) the new definition of your Ingress.
Good luck!