Skip to content

Setup HTTPS certificated

Wildcard certificate with LetsEncrypt

Goal is to have all the url's encryptes with a SSL certificate by LetsEncrypt. I don't want to open http incoming traffic into my homelab from outside, so i will be using the DNS01 challenge type, using Cloudflare as DNS control.

DNS01 challenge

This challenge asks you to prove that you control the DNS for your domain name by putting a specific value in a TXT record under that domain name. It is harder to configure than HTTP-01, but can work in scenarios that HTTP-01 can’t. It also allows you to issue wildcard certificates. After Let’s Encrypt gives your ACME client a token, your client will create a TXT record derived from that token and your account key, and put that record at _acme-challenge.. Then Let’s Encrypt will query the DNS system for that record. If it finds a match, you can proceed to issue a certificate!

For all the following steps to work you must first comply to the following pre-requisites:

  • domain name managed through Cloudflare
  • cert-manager installed

If these pre-requisites are met, the following steps are needed:

  • get cloudflare API token
  • setup cluster issuer
  • setup wildcard certificate
  • forward all incoming http traffic to https

Get cloudflare API-token

From the Cert-manager docs:

Tokens can be created at User Profile > API Tokens > API Tokens. The following settings are recommended:

Permissions:

  • Zone - DNS - Edit
  • Zone - Zone - Read

Zone Resources:

  • Include - All Zones

Now make a Kubernetes secret containing your new API token. This secret will be referenced in the cluster issuer that is created in the next step.

Create a yaml file containing the secret information called cloudflare-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: cloudflare-api-token-secret
type: Opaque
stringData:
  api-token: <API Token>

and apply:

kubectl apply -f cloudflare-secret.yaml

or just use:

kubectl create secret generic cloudflare-api-token-secret --from-literal=api-token=<API Token>

Setup clusterIssuer

An issuer is a resource that represents a certificate authority.

ClusterIssuer from cert-manager docs

Issuers, and ClusterIssuers, are Kubernetes resources that represent certificate authorities (CAs) that are able to generate signed certificates by honoring certificate signing requests.

If you want to create a single Issuer that can be consumed in multiple namespaces, you should consider creating a ClusterIssuer resource. This is almost identical to the Issuer resource, however is non-namespaced so it can be used to issue Certificates across all namespaces.

Since i want to have all certificates issued by LetsEncrypt, a ClusterIssuer is the best to go with.

Create the clusterissuer.yaml file.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    email: <YOUR_EMAIL>
    privateKeySecretRef:
      name: letsencrypt-prod
    server: https://acme-v02.api.letsencrypt.org/directory
    solvers:
    - dns01:
        cloudflare:
          apiTokenSecretRef:
            key: api-token
            name: cloudflare-api-token-secret

and apply

kubectl apply -f clusterissuer.yaml

Check if the registration is succesfull by describing the clusterIssuer

root@cluster-master:~# kubectl describe clusterissuer

Especially the last part is interesting

    Message:               The ACME account was registered with the ACME server
    Observed Generation:   2
    Reason:                ACMEAccountRegistered
    Status:                True
    Type:                  Ready

Setup wildcard certificate

Now the CertificateIssuer is up and running, it's time to get a wildcard certificate up. A certificate is always scoped to a certain namespace. In this case it will be assigned to the kube-system namespace. Since this is a wildcard certificate I want to use for multiple apps in different namespaces, Reflector will take care of copy-ing this certificate to different namespaces. The annotations for this will be added later on.

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-fromej
  namespace: kube-system
spec:
  dnsNames:
  - fromej.nl
  - '*.fromej.nl'
  issuerRef:
    kind: ClusterIssuer
    name: letsencrypt-prod
  secretName: wildcard-k3s-fromej-tls

Warning

Make sure to replace the values in the dnsNames to your own domain.

It might take a minute for the process to finish. Check the status like

root@cluster-master:~# kubectl get certificate -n kube-system
NAME                      READY   SECRET                            AGE
wildcard-fromej           True    wildcard-k3s-fromej-tls           31d

Standard forward HTTP to HTTPS with traefik

Since i want all traffic reaching the Traefik ingress to be rerouted to HTTPS, the traefik chart should be adjusted. The best way to do this, and make sure changes are perserved (also when reboots are done) is via a HelmChartConfig.

cat << 'EOF' | kubectl apply -f -
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
  name: traefik
  namespace: kube-system
spec:
  valuesContent: |-
    ports:
      websecure:
        tls:
          enabled: true
      web:
        redirectTo: websecure
EOF