Zertifikate, insbesondere Probleme mit Zertifikaten, sind eines der meistgehassten Dinge unter den Sysadmins, die ich kenne. In Kubernetes kann Cert-Manager die Zertifikatsverwaltung vereinfachen, indem viele Schritte automatisiert werden. In dieser Anleitung zeige ich dir, wie du Cert-Manager in Kubernetes installierst und verwendest.
Ich habe schon sehr viele Zertifikaten per Hand mit OpenSSL ausgestellt. Daher weiß ich es sehr zu schätzen, dass mir Cert-Manager diese Arbeit in Kubernetes abnimmt.
Was ist Cert-Manager?
Cert-Manager kann als ein Microservice gesehen werden, der in einem Kubernetes-Cluster bereitgestellt wird.Sobald er bereitgestellt und konfiguriert ist, kümmert er sich um das Anfordern, Ausstellen und automatische Erneuern von Zertifikaten.
Wie funktioniert das?
Bei der Installation von Cert-Manager werden auch Cert-Manager-spezifische Custom Resource Definitions (CRDs) wie Definitionen von Zertifikaten, ClusterIssuer und Issuer installiert. Mit diesen CRDs kann man Cert-Manager mitteilen, welche Zertifikate er von wo anfordern soll.
Installation
Cert-Manager kann entweder per Kubernetes-Manifest oder Helm installiert werden. Hier zeige ich dir die Installation über Kubernetes-Manifests, weil es etwas einfacher ist, weniger Schritte erfordert und weniger Dinge zu beachten sind.
Hinweis: Wenn du es per Helm installieren möchtest, empfehle ich dir die offizielle Installationsanleitung.
Im Grunde braucht es nur einen Befehl. Alles, was zu tun ist, ist im Manifest enthalten. Je nachdem, welche Kubernetes-Version du einsetzt, musst du den einen oder anderen Befehl verwenden (höchstwahrscheinlich wird deine Version 1.16 oder höher sein).
Hinweis: Vor der Installation solltest du die aktuellste stabile Version unter https://github.com/jetstack/cert-manager/releases überprüfen und die Version entsprechend ersetzen.
# Für Kubernetes Version 1.16 oder höher
$ kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.1.0/cert-manager.yaml
# Für Kubernetes Version 1.15 oder niedriger
$ kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.1.0/cert-manager-legacy.yaml
Um zu prüfen, ob die Installation erfolgreich war, gib folgendes ein:
$ kubectl get pods --namespace cert-manager
NAME READY STATUS RESTARTS AGE
cert-manager-756bb56c5-6bjfr 1/1 Running 0 56d
cert-manager-webhook-66b555bb5-jfghq 1/1 Running 0 56d
cert-manager-cainjector-86bc6dc648-8pnfc 1/1 Running 0 56d
Du solltest die drei Pods im laufenden Zustand sehen.
Konfigurieren eines Issuers
Bevor Cert-Manager deine Zertifikate verwalten kann, musst du einen Issuer konfigurieren, den er verwenden kann. Der Issuer ist in der Regel ein Dritter sein, der Zertifikate ausstellt und dem andere Computer vertrauen.
Cert-Manager unterstützt verschiedene Arten von Issuer:
- ACME – mit dem ACME-Issuer kannst du Zertifikate von Zertifizierungsstellen anfordern, die das Automated Certificate Management Environment (ACME) Protokoll unterstützen.
- Vault – mit dem Vault-Aussteller kannst du Zertifikate von einer selbst gehosteten Hashicorp Vault Public Key Infrastructure (PKI) abrufen.
- SelfSigned – Damit kannst du selbst signierte Zertifikate ausstellen. Diese werden von anderen Clients standardmäßig nicht als vertrauenswürdig eingestuft.
- CA – mit diesem Aussteller kannst du eine Zertifizierungsstelle innerhalb des Clusters erstellen. Zertifikatsanfragen werden von der lokalen CA signiert. Dieser Aussteller kann hilfreich sein, wenn du gegenseitiges TLS innerhalb des Clusters verwenden möchten.
In dieser Anleitung werden wir den ACME-Issuer verwenden. Mit ACME kannst du Zertifikate von verschiedenen Zertifizierungsstellen beziehen, die das ACME-Protokoll unterstützen – vor allem können Sie damit kostenlose Zertifikate von Let’s Encrypt erhalten. Mittlerweile unterstützen auch einige Enterprise PKI-Lösungen das ACME-Protokoll. Und auch öffentliche CAs wie Digicert unterstützen es.
Issuer oder ClusterIssuer?
Cert-Manager unterstützt zwei Typen von Issuer-Definitionen: ‚Issuer‘ und ‚ClusterIssuer‘. Die ‚Issuer‘-Definition gilt für einen einzelnen Namespace, während die ‚ClusterIssuer‘-Definition für den gesamten Cluster gilt. Je nach deinen Anforderungen solltest du den einen oder anderen verwenden. In dieser Anleitung werden wir den ClusterIssuer mit Let’s Encrypt verwenden.
Let’s Encrypt ClusterIssuer
Wir werden zwei ClusterIssuer für Let’s Encrypt konfigurieren – unter Verwendung der Staging- und der Produktions-API. Zum Testen sollten Sie die Let’s Encrypt Staging-API verwenden, da die Produktions-API ein Rate-Limit hat und dich aussperrt, wenn du zu viele Zertifikate innerhalb einer bestimmten Zeit anforderst.
Um die ClusterIssuers zu konfigurieren, musst du eine yaml-Datei erstellen und diese so anpassen, dass sie zum verwendeten Ingress-Controller passt. Wir werden beide Issuers in dieselbe Datei packen und sie ‚letsencrypt.yml‘ nennen.
--- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-staging spec: acme: # You must replace this email address with your own. # Let's Encrypt will use this to contact you about expiring # certificates, and issues related to your account. email: user@example.com server: https://acme-staging-v02.api.letsencrypt.org/directory privateKeySecretRef: # Secret resource that will be used to store the account's private key. name: staging-issuer-account-key # Add a single challenge solver, HTTP01 solvers: - http01: ingress: # if you use nginx use: # class: nginx lass: traefik --- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: # You must replace this email address with your own. # Let's Encrypt will use this to contact you about expiring # certificates, and issues related to your account. email: user@example.com server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: # Secret resource that will be used to store the account's private key. name: staging-issuer-account-key # Add a single challenge solver, HTTP01 solvers: - http01: ingress: # if you use nginx use: # class: nginx class: traefik
Um sie zu importieren, geben wir ein:
$ kubectl apply -f letsencrypt.yml
clusterissuer.cert-manager.io/letsencrypt-staging configured
clusterissuer.cert-manager.io/letsencrypt-prod configured
Um zu prüfen, ob sie funktionieren, geben wir ein:
$ kubectl describe ClusterIssuer Name: letsencrypt-prod Namespace: Labels: <none> Annotations: <none> API Version: cert-manager.io/v1 Kind: ClusterIssuer Metadata: Creation Timestamp: 2020-05-08T16:25:35Z Generation: 1 Resource Version: 203187 UID: 2f04f031-174c-426b-bf0c-c6a3b7658454 Spec: Acme: Email: user@example.com Preferred Chain: Private Key Secret Ref: Name: prod-issuer-account-key Server: https://acme-v02.api.letsencrypt.org/directory Solvers: http01: Ingress: Class: traefik Selector: Status: Acme: Last Registered Email: user@example.com Uri: https://acme-v02.api.letsencrypt.org/acme/acct/85621721 Conditions: Last Transition Time: 2020-05-08T16:25:37Z Message: The ACME account was registered with the ACME server Reason: ACMEAccountRegistered Status: True Type: Ready Events: <none> ...
Wenn der Status wie oben aussieht, sollte der ClusterIssuer funktionieren.
Zertifikate automatisch über eine Ingress-Definition ausstellen
Um den Let’s Encrypt Issuer mit einem Ingress zu verwenden, musst du deine Ingress-Definitionen anpassen:
- Die Annotation ‚cert-manager.io/cluster-issuer‘ oder ‚cert-manager. io/issuer‘ muss vorhanden sein und den Namen des zu verwendenden Issuers angeben
- Der TLS-Abschnitt muss vorhanden sein:
- Ein oder mehrere Hosts müssen vorhanden sein
- Der secretName muss angegeben werden (das Zertifikat wird dort gespeichert)
- Natürlich müssen die angegebenen Hostnamen auf Ihren Kubernetes Ingress zeigen.
--- apiVersion: extensions/v1 kind: Ingress metadata: annotations: # Specify which ClusterIssuer to use # cert-manager.io/issuer: acme123 # cert-manager.io/cluster-issuer: letsencrypt-prod cert-manager.io/cluster-issuer: letsencrypt-staging name: web1.example.com namespace: web1-example spec: rules: - host: web1.example.com http: paths: - backend: serviceName: web1-example servicePort: 80 tls: - hosts: - web1.example.com - web2.example.com secretName: web1.example.com-tls
Wenn der Ingress in Kubernetes deployed wird, liest Cert-Manager ihn aus und fordert automatisch das Zertifikat vom ClusterIssuer an. Die ACME CA überprüft dann, ob der Host den Besitz des Hostnamens nachweisen kann, indem sie sich mit ihm verbindet und prüft, ob der Challenge-String gefunden werden kann.
Um zu prüfen, ob das Zertifikat korrekt ausgestellt wurde, kannst du folgendes eingeben:
$ kubectl describe certificate -n test Name: web1.example.com-tls Namespace: test Annotations: <none> API Version: cert-manager.io/v1 Kind: Certificate Metadata: Creation Timestamp: 2020-12-29T07:52:12Z ... Spec: Dns Names: web1.example.com web2.example.com Issuer Ref: Group: cert-manager.io Kind: ClusterIssuer Name: letsencrypt-prod Secret Name: web1.example.com-tls Status: Conditions: Last Transition Time: 2020-12-29T07:52:41Z Message: Certificate is up to date and has not expired Reason: Ready Status: True Type: Ready Not After: 2021-03-29T06:52:40Z Not Before: 2020-12-29T06:52:40Z Renewal Time: 2021-02-27T06:52:40Z Revision: 1 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal GeneratedKey 4m56s cert-manager Generated a new private key Normal Requested 4m56s cert-manager Created new CertificateRequest resource "web1.example.com-tls-2067939407" Normal Issued 4m32s cert-manager Certificate issued successfully
Zertifikate über die Zertifikatsressourcen anfordern
Eine weitere Methode, um Zertifikate anzufordern, ist die Verwendung der ‚Certificate‘ Ressource. Für diese Methode musst du eine Ressource wie die folgende erstellen und Cert-Manager kümmert sich um den Rest. Hierfür empfehle ich dir die offizielle Dokumentation zu lesen.
Weitere Lektüre
- Issuer Typen: https://cert-manager.io/docs/configuration/
- ACME: https://cert-manager.io/docs/configuration/acme/
- Sicherung von Ingress-Ressourcen: https://cert-manager.io/docs/usage/ingress/
- Zertifikatsressourcen: https://cert-manager.io/docs/usage/certificate/