Kubernetes TLS Zertifikate
Zertifikate spielen in einem Kubernetes Cluster eine wichtige Rolle:
Durch Zertifikate wird eine Vertrauensbeziehung ausgedrückt.
Vor allem bei einer statischen Beziehung zwischen Services lässt sich eine Authentifizierung durch TLS Zertifikate sehr effizient ausdrücken.
Kubernetes bringt daher auch typischerweise eine eigene Certificate Authority (CA) mit, die als Trust-Root für alle im Kubernetes Cluster verwendeten Zertifikate dienen kann.
Eine eigene CA kann, je nach verwendeten Verfahren zur Cluster Einrichtung, ebenfalls verwendet werden, oder es können intermediate-CA Zertifikate eingesetzt werden.
Standard ist jedoch dass jeder Kubernetes Cluster über eine eigene CA verfügt.
Wie man mit dieser CA interagieren kann wird in diesem Beitrag erklärt.
Kubernetes TLS-Zertifikat-Anfragen erstellen
Um in Kubernetes TLS-Zertifikate auszustellen braucht es nicht viel: Ein Certificate Signing Request (CSR) und ein wenig Interaktion mit der Kubernetes API.
Als Beispiel zum Umgang mit den Zertifikaten wird für eine Docker Registry im Kubernetes Cluster ein passendes Zertifiakt erzeugt. Da die Docker Registry unter unterschiedlichen Namen verfügbar ist, benötigt das TLS-Zertifikat neben dem Common Name auch weitere Subject Alternative Name (SAN) Einträge.
TLS erlaubt sowohl IP-Adressen, als auch DNS-Namen als alternative Subjects, für die ein Zertifikat gültigt ist. Damit kann ein Zugriff sowohl über einen voll qualifizierten Namen, als auch über kurze Namen innerhalb eines Kubernetes Namespace erfolgen.
Zunächst wird ein privater Schlüssel für das Zertifikat benötigt. Mit dem Schlüssel lässt sich dann ein Certificate Signing Request (CSR) erstellen, der an Kubernetes übermittelt wird, um anschließend signiert zu werden.
Um einen neuen Schlüssel und CSR zu erstellen gibt es diverse Werkzeuge. Aktuelle Versionen von OpenSSL erlauben ohne zusätzliche Konfigurationsdateien entsprechende Zertifikatsanfragen zu generieren.
$ openssl genrsa -out server.key 2048 # (1)
Generating RSA private key, 2048 bit long modulus (2 primes)
............................................................+++++
.......+++++
e is 65537 (0x010001)
$ openssl req -new -key server.key -out server.csr \ #(2)
-subj "/CN=localhost" \ #(3)
-addext \ #(4)
"subjectAltName=DNS:registry.docker-registry,DNS:registry.docker-registry.svc.cluster.local"
-
Generierung eines privaten 2048 bit RSA Schlüssels
-
Erstellung eines Certificate Signing Requests
-
Für den Hostnamen localhost
-
zusätzlich soll das Zertifikat für
registry.docker-registry
undregistry.docker-registry.svc.cluster.local
gültig sein
Mit dieser Zertifikatsanfrage kann Kubernetes angesprochen werden.
TLS Zertifikatanfrage in Kubernetes
Eine so erstellte Zertifikatanfrage kann an Kubernetes übermittelt werden. Dazu muss die Anfrage als base64 gekapselte Zeichenkette in dem API Aufruf eingebettet werden.
Ein Beispiel einer solchen Anfrage kann so erstellt werden:
$ cat <<EOF | kubectl create -f -
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
name: registry.docker-registry
spec:
groups:
- system:authenticated
request: $(cat server.csr | base64 | tr -d '\n')
usages:
- digital signature
- key encipherment
- server auth
EOF
certificatesigningrequest.certificates.k8s.io/registry.docker-registry created
Ein entsprechend berechtigter Nutzer kann diese Zertifikatanfrage bestätigen und damit die Signatur der Anfrage auslösen. Kubernetes erstellt daraufhin ein von der Kubernetes Root-CA signiertes Zertifikat, das über die Kubernetes API abgerufen werden kann.
Alle ausstehenden Zertifikatanfragen können mit kubectl get csr
abgerufen werden.
Vergleichbar mit anderen Cluster-Resourcen gibt es keine Trennung in Namespaces für die TLS Zertifikate
$ kubectl get csr
registry.docker-registry 18s kubernetes-admin Pending
$ kubectl describe csr registry.docker-registry
Name: registry.docker-registry
Labels: <none>
Annotations: <none>
CreationTimestamp: Thu, 29 Jan 2019 14:42:13 +0100
Requesting User: kubernetes-admin
Status: Pending
Subject:
Common Name: localhost
Serial Number:
Subject Alternative Names:
DNS Names: registry.docker-registry
registry.docker-registry.svc.cluster.local
Events: <none>
Mit kubectl certificate approve registry.docker-registry
kann das Zertifikat nun ausgestellt werden.
Abgerufen wird das Zertifikat wieder durch kubectl get csr
- der Inhalt des Feldes status.certificate
enthält das signierte TLS Zertifikat.
Auch hier wird ein Base64 Encoding verwendet.
Anschließend kann das CSR Objekt durch kubectl delete csr
wieder gelöscht werden.
$ kubectl certificate approve registry.docker-registry
certificatesigningrequest.certificates.k8s.io/registry.docker-registry approved
$ kubectl get csr
NAME AGE REQUESTOR CONDITION
registry.docker-registry 5m33s kubernetes-admin Approved,Issued
$ kubectl get csr registry.docker-registry -o jsonpath='{.status.certificate}' | base64 --decode > server.crt
$ kubectl delete csr registry.docker-registry
certificatesigningrequest.certificates.k8s.io "registry.docker-registry" deleted
Um das ausgestellte Zertifikat anzusehen, kann OpenSSL verwendet werden.
$ openssl x509 -text -in server.crt
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
22:65:46:3c:7d:75:3c:bb:35:fd:d8:d2:6f:31:4d:2b:8d:88:93:6f
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = kubernetes
Validity
Not Before: Jan 29 13:42:00 2019 GMT
Not After : Jan 29 13:42:00 2020 GMT
Subject: CN = localhost
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:db:33:...
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
28:42:05:D9:60:0C:BE:BE:73:B5:A1:A3:9B:E5:58:BA:0C:28:85:C0
X509v3 Subject Alternative Name:
DNS:registry.docker-registry, DNS:registry.docker-registry.svc.cluster.local
Signature Algorithm: sha256WithRSAEncryption
18:1d:...
-----BEGIN CERTIFICATE-----
MIIDX...
-----END CERTIFICATE-----
Das Zertifikat kann nun verwendet werden, um den Dienst registry.docker-registry
auszuweisen.
Da Credentials aus Sicherheitsgründen nicht fest in einem Container Image eingebaut werden sollten, wird einer Anwendung in Kubernetes das Zertifikat am besten als Secret zur Verfügung gestellt.
Kubernetes verfügt sogar über einen speziellen Secret-Typ für TLS Zertifikate.
TLS Zertifikate als Kubernetes Secret
Um TLS Zertifikate für ein Deployment oder Pod durch Kubernetes bereitzustellen, wird das vorher erzeugte Secret analog zu anderen Secrets deklariert und für die relevanten Container bereitgestellt.
Einzig gilt es zu beachten, dass die Dateinamen dabei vorbelegt sind:
Für das Zertifikat wird tls.crt
und für den Secret-Key wird tls.key
als Dateiname verwendet.
Zur Erzeugung des Secret wird statt des häufig anzutreffenden generic
Typ für das create secret
Kommando dann tls
verwendet.
$ kubectl create secret tls --cert=certs/server.crt --key=certs/server.key registry-tls
Die im Namespace vorhandenen Secrets können zur Überprüfung abgefragt werden.
Bei TLS Zertifikaten ist der Typ dann als kubernetes.io/tls
angegeben.
Soll ein Secret genauer inspiziert werden, kann kubectl describe secret
mit dem Namen des Secrets verwendet werden.
$ kubectl get secret
NAME TYPE DATA AGE
registry-tls kubernetes.io/tls 2 5m
$ kubectl describe secret registry-tls
Name: registry-tls
Namespace: docker-registry
Labels: <none>
Annotations: <none>
Type: kubernetes.io/tls
Data
====
tls.crt: 1229 bytes
tls.key: 1675 bytes
Um das TLS Zertifikat verwenden zu können, muss das Secret im Pod deklariert werden. Secrets werden als Volumes angegeben und bei den jeweiligen Containern als Volume-Mount eingebunden.
apiVersion: apps/v1
kind: Deployment
metadata:
...
template:
metadata:
spec:
containers:
image: ...
name: ...
volumeMounts:
- mountPath: /tls
name: tls
readOnly: true
...
volumes:
- name: tls
secret:
defaultMode: 420
secretName: registry-tls
Fazit
Mit den gezeigten Werkzeugen kann Kubernetes verwendet werden, um im Cluster als vertrauenswürdig eingestufte TLS Zertifikate auszustellen und für Container bereitzustellen.
Typische Anwendungsfälle für TLS Zertifikate sind die Authentifizierung im Machine-to-machine Kontext, vor allem bei Infrastrukturkomponenten. Kubernetes bringt die erforderlichen APIs mit, um darauf aufbauend Prozesse oder organisatorische Vorgaben zu implementieren.
Zu den Themen Kubernetes, Docker und Cloud Architektur bieten wir sowohl Beratung, Entwicklungsunterstützung als auch passende Schulungen an:
Auch für Ihren individuellen Bedarf können wir Workshops und Schulungen anbieten. Sprechen Sie uns gerne an.