
Früher oder später wirft der Betrieb eines Systems die Frage nach der Sicherheit auf: Gewährleistung der Authentifizierung, Trennung von Rechten, Prüfung und anderer Aufgaben. Für Kubernetes wurden bereits
viele Lösungen entwickelt, mit denen auch in sehr anspruchsvollen Umgebungen Standards eingehalten werden können. Das gleiche Material ist grundlegenden Sicherheitsaspekten gewidmet, die im Rahmen der integrierten Mechanismen von K8 implementiert werden. Zuallererst ist es nützlich für diejenigen, die anfangen, sich mit Kubernetes vertraut zu machen, als Ausgangspunkt für das Studium von Sicherheitsfragen.
Authentifizierung
Kubernetes hat zwei Arten von Benutzern:
- Dienstkonten - Konten, die von der Kubernetes-API verwaltet werden;
- Benutzer - „normale“ Benutzer, die von externen, unabhängigen Diensten kontrolliert werden.
Der Hauptunterschied zwischen diesen Typen besteht darin, dass für Dienstkonten in der Kubernetes-API spezielle Objekte (sie werden als
ServiceAccounts
) vorhanden sind, die an den Namespace und den Satz von Berechtigungsdaten gebunden sind, die im Cluster in Objekten vom Typ Secrets gespeichert sind. Solche Benutzer (Dienstkonten) dienen hauptsächlich zum Verwalten von Zugriffsrechten auf die Kubernetes-API-Prozesse, die in einem Kubernetes-Cluster ausgeführt werden.
Normale Benutzer haben keine Einträge in der Kubernetes-API: Sie müssen von externen Mechanismen verwaltet werden. Sie sind für Personen oder Prozesse gedacht, die außerhalb des Clusters leben.
Jede Anforderung an die API ist entweder an das Dienstkonto oder an den Benutzer gebunden oder wird als anonym betrachtet.
Zu den Benutzerauthentifizierungsdaten gehören:
- Benutzername - Benutzername (Groß- und Kleinschreibung beachten !);
- UID ist eine maschinenlesbare Benutzeridentifikationszeichenfolge, die „konsistenter und eindeutiger als der Benutzername“ ist.
- Gruppen - eine Liste von Gruppen, zu denen der Benutzer gehört;
- Extra - zusätzliche Felder, die vom Autorisierungsmechanismus verwendet werden können.
Kubernetes kann eine Vielzahl von Authentifizierungsmechanismen verwenden: X509-Zertifikate, Inhaber-Token, Authentifizierungs-Proxys, HTTP Basic Auth. Mit diesen Mechanismen kann eine Vielzahl von Autorisierungsschemata implementiert werden: von einer statischen Datei mit Kennwörtern bis zu OpenID OAuth2.
Darüber hinaus sind mehrere Autorisierungsschemata gleichzeitig zulässig. Standardmäßig verwendet der Cluster:
- Dienstkontotoken - für Dienstkonten;
- X509 - für Benutzer.
Die Frage zur Verwaltung von ServiceAccounts geht über den Rahmen dieses Artikels hinaus. Ich empfehle jedoch, auf der
offiziellen Dokumentationsseite mehr über dieses Problem zu erfahren. Wir werden das Problem der Arbeit von X509-Zertifikaten genauer betrachten.
Zertifikate für Benutzer (X.509)
Die klassische Art, mit Zertifikaten zu arbeiten, umfasst:
- Schlüsselgenerierung:
mkdir -p ~/mynewuser/.certs/ openssl genrsa -out ~/.certs/mynewuser.key 2048
- Generierung von Zertifikatsanforderungen:
openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
- Verarbeiten der Zertifikatanforderung mithilfe von Kubernetes-Cluster-CA-Schlüsseln und Abrufen eines Benutzerzertifikats (um ein Zertifikat zu erhalten, müssen Sie ein Konto verwenden, das Zugriff auf den Kubernetes-Clusterzertifikat-Berechtigungsschlüssel hat, der sich standardmäßig in
/etc/kubernetes/pki/ca.key
):
openssl x509 -req -in ~/.certs/mynewuser.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out ~/.certs/mynewuser.crt -days 500
- Erstellen einer Konfigurationsdatei:
- Clusterbeschreibung (geben Sie die Adresse und den Speicherort der CA-Zertifikatdatei der jeweiligen Clusterinstallation an):
kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
- oder - wenn nicht die empfohlene Option - Sie können das Stammzertifikat weglassen (dann prüft kubectl nicht die Richtigkeit des API-Server-Clusters):
kubectl config set-cluster kubernetes --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
- Hinzufügen eines Benutzers zur Konfigurationsdatei:
kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt --client-key=.certs/mynewuser.key
- Kontext hinzufügen:
kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser
- Standardkontextzuweisung:
kubectl config use-context mynewuser-context
Nach den obigen Manipulationen wird eine Konfiguration des Formulars in der
.kube/config
Datei erstellt:
apiVersion: v1 clusters: - cluster: certificate-authority: /etc/kubernetes/pki/ca.crt server: https://192.168.100.200:6443 name: kubernetes contexts: - context: cluster: kubernetes namespace: target-namespace user: mynewuser name: mynewuser-context current-context: mynewuser-context kind: Config preferences: {} users: - name: mynewuser user: client-certificate: /home/mynewuser/.certs/mynewuser.crt client-key: /home/mynewuser/.certs/mynewuser.key
Um die Übertragung der Konfiguration zwischen Konten und Servern zu erleichtern, ist es hilfreich, die Werte der folgenden Schlüssel zu bearbeiten:
certificate-authority
client-certificate
client-key
Dazu können Sie die darin angegebenen Dateien mit base64 codieren und in der Konfiguration registrieren, indem
-data
dem Namen der Schlüssel das Suffix
-data
hinzufügen, d. H. Abrufen von
certificate-authority-data
usw.
Zertifikate mit kubeadm
Mit der Veröffentlichung von
Kubernetes 1.15 ist die Arbeit mit Zertifikaten dank der Alpha-Version der Unterstützung im
Dienstprogramm kubeadm viel einfacher geworden. So könnte beispielsweise die Generierung einer Konfigurationsdatei mit Benutzerschlüsseln jetzt aussehen:
kubeadm alpha kubeconfig user --client-name=mynewuser --apiserver-advertise-address 192.168.100.200
Hinweis : Die erforderliche Anzeigenadresse kann standardmäßig in der API-Server-Konfiguration unter /etc/kubernetes/manifests/kube-apiserver.yaml
angezeigt werden.Die resultierende Konfiguration wird an stdout ausgegeben. Es muss in
~/.kube/config
Benutzerkontos oder in der in der Umgebungsvariablen
KUBECONFIG
angegebenen Datei
KUBECONFIG
.
Tiefer graben
Für diejenigen, die die beschriebenen Probleme gründlich verstehen möchten:
Login
Ein authentifiziertes Konto hat standardmäßig keine Berechtigung, in einem Cluster zu agieren. Kubernetes verfügt über einen Autorisierungsmechanismus zum Erteilen von Berechtigungen.
Vor Version 1.6 verwendete Kubernetes einen Authentifizierungstyp namens
ABAC (Attribute-based Access Control). Details dazu finden Sie in der
offiziellen Dokumentation . Dieser Ansatz wird derzeit als Legacy angesehen, Sie können ihn jedoch gleichzeitig mit anderen Autorisierungsarten verwenden.
Die eigentliche (und flexiblere) Art der Aufteilung der Clusterzugriffsrechte wird als
RBAC (
Role-based Access Control ) bezeichnet. Es wurde seit
Kubernetes 1.8 für stabil erklärt. RBAC implementiert ein Rechte-Modell, das alles verbietet, was nicht ausdrücklich erlaubt ist.
Um RBAC zu aktivieren , müssen Sie den Kubernetes-API-Server mit der Option
--authorization-mode=RBAC
. Die Parameter werden im Manifest mit der API-Server-Konfiguration festgelegt, die sich standardmäßig im Pfad
/etc/kubernetes/manifests/kube-apiserver.yaml
im
command
. RBAC ist jedoch bereits standardmäßig aktiviert, sodass Sie sich darüber wahrscheinlich keine Gedanken machen sollten: Sie können dies anhand des Werts des
authorization-mode
überprüfen (in der bereits erwähnten
kube-apiserver.yaml
). Übrigens kann es unter seinen Werten andere Arten von Berechtigungen geben (
node
,
webhook
,
always allow
), aber wir werden sie außerhalb des Bereichs des Materials
webhook
.
Übrigens haben wir bereits
einen Artikel mit einer ziemlich detaillierten Geschichte über die Prinzipien und Merkmale der Arbeit mit RBAC veröffentlicht, daher beschränke ich mich weiter auf eine kurze Auflistung der Grundlagen und Beispiele.
Die folgenden API-Entitäten werden verwendet, um den Zugriff auf Kubernetes über RBAC zu steuern:
Role
und ClusterRole
sind Rollen, die Berechtigungen beschreiben:Role
können Sie Rechte in einem Namespace beschreiben.ClusterRole
- innerhalb des Clusters, einschließlich ClusterRole
Objekte wie Knoten, Nicht-Ressourcen-URLs (d. H. Nicht in Bezug auf Kubernetes-Ressourcen - z. B. /version
, /logs
, /api*
);RoleBinding
und ClusterRoleBinding
- dient zum Binden von Role
und ClusterRole
an einen Benutzer, eine Benutzergruppe oder ein ServiceAccount.
Entities Role und RoleBinding sind durch den Namespace begrenzt, d. H. muss sich im selben Namespace befinden. RoleBinding kann sich jedoch auf ClusterRole beziehen, mit dem Sie eine Reihe von Standardberechtigungen erstellen und den Zugriff damit steuern können.
Rollen beschreiben Rechte mithilfe von Regelsätzen, die Folgendes enthalten:
- API-Gruppen - siehe die offizielle Dokumentation für apiGroups und die Ausgabe von
kubectl api-resources
; - Ressourcen ( Ressourcen :
pod
, namespace
, deployment
usw.); - Verben ( Verben :
set
, update
usw.). - Ressourcennamen (
resourceNames
) - für den Fall, dass Sie Zugriff auf eine bestimmte Ressource und nicht auf alle Ressourcen dieses Typs gewähren müssen.
Eine ausführlichere Beschreibung der Autorisierung in Kubernetes finden Sie auf der
offiziellen Dokumentationsseite . Stattdessen (oder besser gesagt zusätzlich) werde ich Beispiele geben, die seine Arbeit veranschaulichen.
Beispiele für RBAC-Entitäten
Eine einfache
Role
, mit der Sie die Liste und den Status von Pods abrufen und im
target-namespace
überwachen können:
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: target-namespace name: pod-reader rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "watch", "list"]
Ein Beispiel für
ClusterRole
, mit dem Sie eine Liste und den Status von Pods
ClusterRole
und im gesamten Cluster überwachen können:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: # "namespace" , ClusterRole name: pod-reader rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "watch", "list"]
Beispiel für eine
RoleBinding
, mit der der Benutzer
mynewuser
Pods im
my-namespace
"lesen" kann:
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: read-pods namespace: target-namespace subjects: - kind: User name: mynewuser # ! apiGroup: rbac.authorization.k8s.io roleRef: kind: Role # “Role” “ClusterRole” name: pod-reader # Role, namespace, # ClusterRole, # apiGroup: rbac.authorization.k8s.io
Ereignisprüfung
Schematisch kann die Architektur von Kubernetes wie folgt dargestellt werden:

Die Schlüsselkomponente von Kubernetes, die für die Verarbeitung von Anfragen verantwortlich ist, ist der
API-Server . Alle Vorgänge im Cluster werden durchlaufen. Weitere Informationen zu diesen internen Mechanismen finden Sie im Artikel „
Was passiert in Kubernetes, wenn der Kubectl-Lauf gestartet wird? ".
Die Systemprüfung ist eine interessante Funktion in Kubernetes, die standardmäßig deaktiviert ist. Sie können alle Aufrufe an die Kubernetes-API protokollieren. Wie Sie leicht erraten können, werden über diese API alle Aktionen ausgeführt, die sich auf die Überwachung und Änderung des Status des Clusters beziehen. Eine gute Beschreibung der Funktionen finden Sie (wie üblich) in der
offiziellen K8-
Dokumentation . Als nächstes werde ich versuchen, das Thema in einer einfacheren Sprache darzustellen.
Um die Überwachung zu ermöglichen , müssen drei erforderliche Parameter an den Container im API-Server übergeben werden. Weitere Informationen hierzu finden Sie weiter unten:
--audit-policy-file=/etc/kubernetes/policies/audit-policy.yaml
--audit-log-path=/var/log/kube-audit/audit.log
--audit-log-format=json
Zusätzlich zu diesen drei erforderlichen Parametern gibt es viele zusätzliche Einstellungen für die Überwachung: von der Protokollrotation bis zu Webhook-Beschreibungen. Beispiel für Protokollrotationsparameter:
--audit-log-maxbackup=10
--audit-log-maxsize=100
--audit-log-maxage=7
Wir werden jedoch nicht näher darauf eingehen - alle Details finden Sie in der
Dokumentation zu kube-apiserver .
Wie bereits erwähnt, werden alle Parameter im Manifest mit der API-Server-Konfiguration (standardmäßig
/etc/kubernetes/manifests/kube-apiserver.yaml
) im
command
. Kehren wir zu den 3 erforderlichen Parametern zurück und analysieren sie:
audit-policy-file
- Pfad zur YAML-Datei mit der Beschreibung der Überwachungsrichtlinie. Wir werden zu seinem Inhalt zurückkehren, aber im Moment stelle ich fest, dass die Datei für den API-Server-Prozess zum Lesen zugänglich sein sollte. Daher muss es im Container bereitgestellt werden, für den Sie den folgenden Abschnitten der Konfiguration den folgenden Code hinzufügen können:
volumeMounts: - mountPath: /etc/kubernetes/policies name: policies readOnly: true volumes: - hostPath: path: /etc/kubernetes/policies type: DirectoryOrCreate name: policies
audit-log-path
- Pfad zur Protokolldatei. Der Pfad sollte auch für den API-Server-Prozess zugänglich sein. Daher beschreiben wir in ähnlicher Weise seine Bereitstellung:
volumeMounts: - mountPath: /var/log/kube-audit name: logs readOnly: false volumes: - hostPath: path: /var/log/kube-audit type: DirectoryOrCreate name: logs
audit-log-format
- Format des Überwachungsprotokolls. Standardmäßig ist dies json
, aber das ältere Textformat ist auch verfügbar.
Prüfungsrichtlinien
Nun zur genannten Datei mit der Beschreibung der Protokollierungsrichtlinie. Das erste Konzept der Überwachungsrichtlinie ist die
level
, die
Ebene der Protokollierung . Sie sind wie folgt:
None
- nicht protokollieren;Metadata
- Protokollanforderungsmetadaten: Benutzer, Anforderungszeit, Zielressource (Pod, Namespace usw.), Aktionstyp (Verb) usw.;Request
- Metadaten und Request
protokollieren;RequestResponse
- RequestResponse
Metadaten, Anfragetext und Antworttext.
Die letzten beiden Ebenen (
Request
und
RequestResponse
) protokollieren keine Anforderungen, die nicht auf Ressourcen zugegriffen haben (Aufrufe von sogenannten Nicht-Ressourcen-URLs).
Außerdem durchlaufen alle Anfragen
mehrere Phasen :
RequestReceived
- die Phase, in der die Anforderung vom Handler empfangen wird und noch nicht weiter entlang der Handlerkette übertragen wurde.ResponseStarted
- Antwortheader gesendet, jedoch vor dem Senden des Antwortkörpers. Generiert für lange Abfragen (z. B. watch
);ResponseComplete
- Antworttext gesendet, weitere Informationen werden nicht gesendet.Panic
- Ereignisse werden generiert, wenn ein Notfall erkannt wird.
Sie können
omitStages
, um beliebige Phasen zu überspringen.
In der Richtliniendatei können wir mehrere Abschnitte mit unterschiedlichen Protokollierungsstufen beschreiben. Es gilt die erste Übereinstimmungsregel in der Richtlinienbeschreibung.
Der Kubelet-Daemon überwacht die Manifeständerung mit der API-Server-Konfiguration und startet den Container mit dem API-Server neu, falls eine solche erkannt wird. Es gibt jedoch ein wichtiges Detail:
Sie ignorieren Änderungen an der Richtliniendatei . Nachdem Sie Änderungen an der Richtliniendatei vorgenommen haben, müssen Sie den API-Server manuell neu starten. Da der API-Server als
statischer Pod ausgeführt wird , wird er vom Befehl
kubectl delete
nicht neu
kubectl delete
. Sie müssen
docker stop
manuell auf Kube-Mastern
docker stop
auf denen die Überwachungsrichtlinie geändert wurde:
docker stop $(docker ps | grep k8s_kube-apiserver | awk '{print $1}')
Wenn Sie die
Überwachung aktivieren, ist es wichtig zu
beachten, dass
kube-apiserver eine höhere Last hat . Insbesondere steigt der Speicherverbrauch zum Speichern des Kontextes von Anforderungen. Die Protokollierung beginnt erst nach dem Senden des Antwortheaders. Die Auslastung hängt auch von der Konfiguration der Überwachungsrichtlinie ab.
Richtlinienbeispiele
Lassen Sie uns die Struktur von Richtliniendateien anhand von Beispielen analysieren.
Hier ist eine einfache
policy
, um alles auf
Metadata
zu protokollieren:
apiVersion: audit.k8s.io/v1 kind: Policy rules: - level: Metadata
Sie können eine Liste von Benutzern (
Users
und
ServiceAccounts
) und Benutzergruppen in der Richtlinie angeben. Auf diese Weise ignorieren wir beispielsweise Systembenutzer, protokollieren jedoch alles andere auf
Request
:
apiVersion: audit.k8s.io/v1 kind: Policy rules: - level: None userGroups: - "system:serviceaccounts" - "system:nodes" users: - "system:anonymous" - "system:apiserver" - "system:kube-controller-manager" - "system:kube-scheduler" - level: Request
Es ist auch möglich, das Ziel zu beschreiben:
namespaces
- Verben ( Verben :
get
, update
, delete
und andere); - Ressourcen ( Ressourcen , nämlich:
pod
, configmaps
usw.) und Ressourcengruppen ( apiGroups
).
Beachten Sie! Ressourcen und Ressourcengruppen (API-Gruppen, d. H. ApiGroups) sowie deren im Cluster installierte Versionen können mit den folgenden Befehlen abgerufen werden:
kubectl api-resources kubectl api-versions
Die folgende Prüfungsrichtlinie dient als Demonstration der Best Practices in der
Alibaba Cloud-Dokumentation :
apiVersion: audit.k8s.io/v1beta1 kind: Policy # RequestReceived omitStages: - "RequestReceived" rules: # , : - level: None users: ["system:kube-proxy"] verbs: ["watch"] resources: - group: "" # api group , # Kubernetes, “core” resources: ["endpoints", "services"] - level: None users: ["system:unsecured"] namespaces: ["kube-system"] verbs: ["get"] resources: - group: "" # core resources: ["configmaps"] - level: None users: ["kubelet"] verbs: ["get"] resources: - group: "" # core resources: ["nodes"] - level: None userGroups: ["system:nodes"] verbs: ["get"] resources: - group: "" # core resources: ["nodes"] - level: None users: - system:kube-controller-manager - system:kube-scheduler - system:serviceaccount:kube-system:endpoint-controller verbs: ["get", "update"] namespaces: ["kube-system"] resources: - group: "" # core resources: ["endpoints"] - level: None users: ["system:apiserver"] verbs: ["get"] resources: - group: "" # core resources: ["namespaces"] # read-only URLs: - level: None nonResourceURLs: - /healthz* - /version - /swagger* # , “”: - level: None resources: - group: "" # core resources: ["events"] # Secret, ConfigMap TokenReview , # - level: Metadata resources: - group: "" # core resources: ["secrets", "configmaps"] - group: authentication.k8s.io resources: ["tokenreviews"] # get, list watch ; - level: Request verbs: ["get", "list", "watch"] resources: - group: "" # core - group: "admissionregistration.k8s.io" - group: "apps" - group: "authentication.k8s.io" - group: "authorization.k8s.io" - group: "autoscaling" - group: "batch" - group: "certificates.k8s.io" - group: "extensions" - group: "networking.k8s.io" - group: "policy" - group: "rbac.authorization.k8s.io" - group: "settings.k8s.io" - group: "storage.k8s.io" # API - level: RequestResponse resources: - group: "" # core - group: "admissionregistration.k8s.io" - group: "apps" - group: "authentication.k8s.io" - group: "authorization.k8s.io" - group: "autoscaling" - group: "batch" - group: "certificates.k8s.io" - group: "extensions" - group: "networking.k8s.io" - group: "policy" - group: "rbac.authorization.k8s.io" - group: "settings.k8s.io" - group: "storage.k8s.io" # - level: Metadata
Ein weiteres gutes Beispiel für eine Prüfungsrichtlinie ist das
in GCE verwendete Profil .
Für eine schnelle Reaktion auf
Überwachungsereignisse kann ein Webhook beschrieben werden . Dieses Problem wird in der
offiziellen Dokumentation offengelegt. Ich werde es außerhalb des Geltungsbereichs dieses Artikels belassen.
Zusammenfassung
Der Artikel bietet einen Überblick über grundlegende Sicherheitsmechanismen in Kubernetes-Clustern, mit denen Sie personalisierte Benutzerkonten erstellen, deren Rechte freigeben und deren Aktionen aufzeichnen können. Ich hoffe, es ist nützlich für diejenigen, die in der Theorie oder bereits in der Praxis mit solchen Fragen konfrontiert sind. Ich empfehle Ihnen auch, sich die Liste anderer Materialien zum Thema Sicherheit in Kubernetes anzusehen, die in der "PS" aufgeführt ist. Vielleicht finden Sie unter ihnen die erforderlichen Details zu Themen, die für Sie relevant sind.
PS
Lesen Sie auch in unserem Blog: