Deploying K3s with Ansible - Part 3
Day 6 - Deploying Cert-Manager with ansible
Cert-manager is a Kubernetes native certificate management controller. It helps automate the management and issuance of TLS certificates from various certificate authorities (CAs) such as Let’s Encrypt, Venafi, HashiCorp Vault, or a custom CA. I am going to use this in conjunction with emberstacks reflector so that when I create a new certificate for my homelab I can mirror that certificate to more than one namespace.
In Kubernetes, a namespace is a virtual cluster or a logical partition of Kubernetes resources within a Kubernetes cluster. It’s a way to divide cluster resources between multiple users (or teams) and provide a scope for Kubernetes objects.
I will be using LetsEncrypt to generate the certificates for my homelab, this way anything I self host will always have a certificate and I can avoid the warning when I use the services.
Installing Cert-Manager
I will re-use a lot of the same process from the previous post. These steps are pretty much straight from the Helm Chart for cert-manager
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
---
### Installing Cert Manager
- block:
- name: Add jetstack Helm repository
kubernetes.core.helm_repository:
name: jetstack
repo_url: https://charts.jetstack.io
- name: Update Helm jetstack repositories
kubernetes.core.helm_repository:
name: jetstack
repo_url: https://charts.jetstack.io
force_update: yes
- name: Create cert-manager namespace
kubernetes.core.k8s:
api_version: v1
kind: Namespace
name: cert-manager
state: present
- name: Apply cert-manager CRDs
kubernetes.core.k8s:
state: present
src: "https://github.com/cert-manager/cert-manager/releases/download/v{{certmanager_version}}/cert-manager.crds.yaml"
- name: Install cert-manager Helm chart
kubernetes.core.helm:
name: cert-manager
chart_ref: jetstack/cert-manager
release_namespace: cert-manager
values: "{{ cert_manager }}"
chart_version: "{{ certmanager_version }}"
state: present
Setting up a cloudflare secret and installing reflector
The secret being created here is so that cert-manager and can validate that you own the domain that you are using for the certificates.
1
2
3
4
5
6
7
- name: Apply issuers secrets
kubernetes.core.k8s:
state: present
definition: "{{ lookup('template', 'secret-cf-token.j2') }}"
./roles/install-cert-manager/templates/secret-cf-token.j2:
1
2
3
4
5
6
7
8
9
10
11
---
apiVersion: v1
kind: Secret
metadata:
name: cloudflare-token-secret
namespace: cert-manager
type: Opaque
stringData:
cloudflare-token: {{ cf_token }}
Next Task:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- name: Add emberstack Helm repository
kubernetes.core.helm_repository:
name: emberstack
repo_url: https://emberstack.github.io/helm-charts
- name: Update Helm repository
kubernetes.core.helm_repository:
name: emberstack
repo_url: https://emberstack.github.io/helm-charts
force_update: yes
- name: Install reflector Helm chart
kubernetes.core.helm:
name: reflector
chart_ref: emberstack/reflector
release_namespace: default
state: present
This configuration sets up a ClusterIssuer resource named letsencrypt-staging, which uses Let’s Encrypt’s staging environment for issuing TLS certificates and employs Cloudflare for DNS challenge validation.
testing with a staging environment before obtaining a real certificate helps ensure a smooth and error-free deployment of TLS certificates in production environments while minimizing risks associated with misconfigurations or excessive certificate requests. LetsEncrypt rate limits and this will avoid being limited from requested certificates.
1
2
3
4
5
6
- name: Apply Staging ClusterIssuer
kubernetes.core.k8s:
state: present
definition: "{{ lookup('template', 'letsencrypt-staging.j2') }}"
./roles/install-cert-manager/templates/letsencrypt-staging.j2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: {{ cf_email }}
privateKeySecretRef:
name: letsencrypt-staging
solvers:
- dns01:
cloudflare:
email: {{ cf_email }}
apiTokenSecretRef:
name: cloudflare-token-secret
key: cloudflare-token
selector:
dnsZones: {{ cf_zones }}
Now we can request the certificate from LetsEncrypt, The ‘Get challenges’ task will check the challenge of the LetsEncrypt check of the cloudflare dns to ensure you are the owner of the domain. I then store the certificate and key in another folder so that I have them incase I need them again later on.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- name: Generate Staging Certificate
kubernetes.core.k8s:
state: present
definition: "{{ lookup('template', 'stage-local-byrnbaker-me.j2') }}"
- name: Get challenges
kubernetes.core.k8s_info:
kind: Challenge
namespace: default
register: result
until: result.resources | length == 0
retries: 20
delay: 30
- name: Capture the certificate for use later
shell: |
kubectl get secret {{ staging_secret }} -n default -o jsonpath="{.data.tls\.crt}" | base64 --decode > ./generated_certificate/staging-tls.crt
- name: Capture the certificate for use later
shell: |
kubectl get secret {{ staging_secret }} -n default -o jsonpath="{.data.tls\.key}" | base64 --decode > ./generated_certificate/staging-tls.key
tags: staging-install
This block of tasks would be run with the tag at command line.
1
ansible-playbook install-traefik.yml --tags "staging-install"