cert-manager
Transport-Layer Verschlüsselung per Secure Sockets Layer (SSL) bzw. Transport Layer Security (TLS) ist ‘state of the art’. Kaum eine Webseite kommt mehr ohne Verschlüsselung auf Transportprotokoll-Ebene aus.
Zum Glück ist es seit es Let’s Encrypt gibt, kaum mehr ein Problem, an ein gültiges TLS-Zertifikat zu kommen, dass von einer Zertifizierungstelle signiert wurde, die die meisten Browser und Betriebssysteme als vertrauenwürdig einstufen.
Mit cert-manager gibt es eine komfortable Lösung zur Verwaltung von SSL-Zertifikaten im Kubernetes-Cluster.
cert-manager
cert-manager ist eine Komponente, um das Management von TLS Zertifikaten zu automatisieren. Dazu nutzt cert-manager das Protokoll ACME (Automatic Certificate Management Environment), das vor allem im Zusammenhang mit Let’s Encrypt bekannt sein dürfte. Neben Let’s Encrypt werden aber auch viele weitere Zertifikatstellen oder sichere Ablagemöglichkeiten für Geheimnisse z.B. Hashicorp Vault unterstützt.
cert-manager prüft regelmäßig ob Zertifikate gültig und aktuell sind und erneuert sie rechtzeitig vor deren Ablauf.
Ich beschreibe im folgenden zunächst die manuelle Installation per Helm und gehe danach darauf ein, wie die Konfiguration für Flux v2 aussieht. Für Informationen zu Flux und GitOps verweise ich hier auf den Blogpost GitOps
Installation per Helm
cert-manager kann per Helm installiert werden. Die Quellen für die Zertifikate, die sogenannten Issuer (gültig innerhalb des jeweiligen Namespaces) bzw. ClusterIssuer (Clusterweit gültig), müssen per kubectl
installiert werden.
# Namespace for cert-manager resources
kubectl create namespace cert-manager
# Add helm repository
helm repo add jetstack https://charts.jetstack.io
# Update helm repository
helm repo update
helm install \
cert-manager jetstack/cert-manager \
--namespace cert-manager \
--version v1.1.0 \
--set installCRDs=true
ClusterIssuer erzeugen
Wir erzeugen zwei ClusterIssuer, die die Let’s encrypt (Produktiv- bzw. Entwicklungs-Instanz) nutzen.
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
email: <your-mail-address>
solvers:
- selector: {}
http01:
ingress:
class: nginx
privateKeySecretRef:
name: letsencrypt-staging
server: https://acme-staging-v02.api.letsencrypt.org/directory
---
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
email: <your-mail-address>
solvers:
- selector: {}
http01:
ingress:
class: nginx
privateKeySecretRef:
name: letsencrypt-prod
server: https://acme-v02.api.letsencrypt.org/directory
# Create cluster-issuer
kubectl apply -f cluster-issuer.yaml
GitOps / flux
Zunächst erzeugen wir das Verzeichnis für unseren cert-manager.
# Create directory cert-manager
mkdir infrastructure/cert-manager
Danach fügen wir im kustomizations Manifest im Verzeichnis infrastructure
unter resources
die Zeile - ./cert-manager
ein.
Im infrastructure/sources
-Verzeichnis legen wir die Datei jetstack.yaml
mit dem HelmRepository-Kubernetes-Manifest an. Die Datei sollte folgenden Inhalt enthalten.
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: HelmRepository
metadata:
name: jetstack
spec:
interval: 30m
url: https://charts.jetstack.io
Nun legen wir die Dateien infrastructure/cert-manager/namespace.yaml
und infrastructure/cert-manager/release.yaml
an.
apiVersion: v1
kind: Namespace
metadata:
name: cert-manager
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: cert-manager
spec:
releaseName: cert-manager
chart:
spec:
chart: cert-manager
sourceRef:
kind: HelmRepository
name: cert-manager
namespace: flux-system
version: v1.1.0
interval: 1h0m0s
install:
remediation:
retries: 3
values:
installCRDs: true
Jetzt benötigen wir noch die Dateikustomization.yaml
, die namespace.yaml
und release.yaml
referenziert.
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: cert-manager
resources:
- namespace.yaml
- release.yaml
Um schließlich auch die ClusterIssuer per GitOps zu erzeugen, erstellen wir noch die Datei infrastructure/cert-manager/clusterissueres.yaml
und referenzieren sie in der kustomizations-Datei.
Dazu fügen wir in der Datei kustomizations.yaml
unter resources
die Zeile - clusterissuers.yaml
ein.
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
email: <your mailadress>
solvers:
- selector: {}
http01:
ingress:
class: nginx
privateKeySecretRef:
name: letsencrypt-staging
server: https://acme-staging-v02.api.letsencrypt.org/directory
---
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
email: <your mailadress>
solvers:
- selector: {}
http01:
ingress:
class: nginx
privateKeySecretRef:
name: letsencrypt-prod
server: https://acme-v02.api.letsencrypt.org/directory
Wir sind nun in der Lage, in unserem Kubernetes-Cluster Webanwendungen bzw. Services wie diesen Blog zu betreiben. Mit einem Ingress können wir Webseiten oder APIs auch außerhalb des Kubernetes-Clusters erreichbar machen. Um Verbindungen auf Transportebene zu verschlüsseln können wir SSL/TLS nutzen und die dafür notwendigen Zertifikate automatisch von Let’s Encrypt beziehen und installieren.
Wenn wir uns nicht wie dieser Blog auf einen statischen Webseiten-Generator wie Hugo beschränken wollen, sondern z.B. Wordpress nutzen möchten, benötigen wir die Möglichkeit, Daten persistent zu speichern. Im nächsten Blogpost wird es darum um das Thema Persistenz im Kubernetes-Cluster gehen.