Kapitel 4. Konfiguration, Geheimnisse und RBAC

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

Die Kompositionsfähigkeit von Containern ermöglicht es uns als Betreibern, zur Laufzeit Konfigurationsdaten in einen Container einzubringen. So können wir die Funktion einer Anwendung von der Umgebung entkoppeln, in der sie läuft. Mithilfe der Konventionen, die in der Container-Laufzeit erlaubt sind, um entweder Umgebungsvariablen oder externe Datenträger zur Laufzeit in einen Container einzubinden, kannst du die Konfiguration der Anwendung bei ihrer Instanziierung effektiv ändern. Als Entwickler ist es wichtig, die Dynamik dieses Verhaltens zu berücksichtigen und die Verwendung von Umgebungsvariablen oder das Lesen von Konfigurationsdaten aus einem bestimmten Pfad zu ermöglichen, der dem Benutzer zur Laufzeit der Anwendung zur Verfügung steht.

Wenn du sensible Daten wie Geheimnisse in ein natives Kubernetes-API-Objekt verschiebst, ist es wichtig zu verstehen, wie Kubernetes den Zugriff auf die API sichert. Die am häufigsten in Kubernetes eingesetzte Sicherheitsmethode ist die rollenbasierte Zugriffskontrolle (Role-Based Access Control, RBAC), mit der eine fein abgestufte Berechtigungsstruktur für Aktionen implementiert wird, die von bestimmten Nutzern oder Gruppen an der API durchgeführt werden können. In diesem Kapitel werden einige der bewährten Methoden für RBAC vorgestellt und eine kleine Einführung gegeben.

Konfiguration durch ConfigMaps und Secrets

Kubernetes ermöglicht es dir, Konfigurationsinformationen über ConfigMaps oder geheime Ressourcen an unsere Anwendungen weiterzugeben. Der Hauptunterschied zwischen den beiden ist die Art und Weise, wie ein Pod die empfangenden Informationen speichert und wie die Daten im etcd-Datenspeicher abgelegt werden.

ConfigMaps

ist es üblich, dass Anwendungen Konfigurationsinformationen über einen Mechanismus wie Befehlszeilenargumente, Umgebungsvariablen oder Dateien, die dem System zur Verfügung stehen, abrufen. Mit Containern kann der Entwickler diese Konfigurationsinformationen von der Anwendung entkoppeln, was eine echte Portabilität der Anwendung ermöglicht. Die ConfigMap-API ermöglicht die Injektion von bereitgestellten Konfigurationsinformationen. ConfigMaps sind sehr anpassungsfähig an die Anforderungen der Anwendung und können Schlüssel/Wertpaare oder komplexe Massendaten wie JSON, XML oder proprietäre Konfigurationsdaten bereitstellen.

Die ConfigMaps liefern nicht nur Konfigurationsinformationen für Pods, sondern auch Informationen, die für komplexere Systemdienste wie Controller, CRDs, Operatoren usw. verwendet werden können. Wie bereits erwähnt, ist die ConfigMap-API eher für String-Daten gedacht, die keine wirklich sensiblen Daten sind. Wenn deine Anwendung sensiblere Daten benötigt, ist die Secrets-API besser geeignet.

Damit deine Anwendung die ConfigMap-Daten nutzen kann, können sie entweder als in den Pod eingebundenes Volume oder als Umgebungsvariable injiziert werden.

Geheimnisse

Viele der Eigenschaften und Gründe, aus denen du eine ConfigMap verwenden möchtest, gelten auch für Geheimnisse. Die Hauptunterschiede liegen in der grundlegenden Natur eines Geheimnisses. Geheime Daten sollten so gespeichert und gehandhabt werden, dass sie leicht versteckt und möglicherweise im Ruhezustand verschlüsselt werden können, wenn die Umgebung so konfiguriert ist. Die geheimen Daten werden als base64-kodierte Informationen dargestellt, und es ist wichtig zu verstehen, dass diese nicht verschlüsselt sind. Sobald das Geheimnis in den Pod injiziert wird, kann der Pod selbst die geheimen Daten im Klartext sehen.

Geheime Daten sind für kleine Datenmengen gedacht, die in Kubernetes standardmäßig auf eine Größe von 1 MB für die base64-kodierten Daten begrenzt sind. Achte also darauf, dass die tatsächlichen Daten wegen des Overheads der Kodierung etwa 750 KB groß sind. Es gibt drei Arten von Secrets in Kubernetes:

generic

Bei handelt es sich in der Regel um reguläre Schlüssel/Wert-Paare, die mit dem Parameter --from-literal= aus einer Datei, einem Verzeichnis oder aus String-Literalen erstellt werden, wie folgt:

kubectl create secret generic mysecret --from-literal=key1=$3cr3t1
    --from-literal=key2=@3cr3t2
docker-registry

Diese wird vom Kubelet verwendet, wenn es in einem Pod-Template eine imagePullsecret gibt, um die Anmeldedaten für die Authentifizierung bei einer privaten Docker-Registry bereitzustellen:

kubectl create secret docker-registry registryKey --docker-server
    myreg.azurecr.io --docker-username myreg --docker-password
    $up3r$3cr3tP@ssw0rd --docker-email ignore@dummy.com
tls

erstellt ein TLS-Geheimnis (Transport Layer Security) aus einem gültigen öffentlichen/privaten Schlüsselpaar. Solange das Zertifikat in einem gültigen PEM-Format vorliegt, wird das Schlüsselpaar als Geheimnis kodiert und kann an den Pod zur Verwendung für SSL/TLS übergeben werden:

kubectl create secret tls www-tls --key=./path_to_key/wwwtls.key
    --cert=./path_to_crt/wwwtls.crt

Geheimnisse werden auch nur auf den Knoten in tmpfs gemountet, die einen Pod haben, der das Geheimnis benötigt, und werden gelöscht, wenn der Pod, der das Geheimnis benötigt, verschwunden ist. Dadurch wird verhindert, dass Geheimnisse auf der Festplatte des Knotens zurückbleiben. Obwohl dies sicher zu sein scheint, ist es wichtig zu wissen, dass Geheimnisse standardmäßig im etcd-Datenspeicher von Kubernetes im Klartext gespeichert werden. Daher ist es wichtig, dass die Systemadministratoren oder der Cloud-Provider Maßnahmen ergreifen, um die Sicherheit der etcd-Umgebung zu gewährleisten, einschließlich mTLS zwischen den etcd-Knoten und der Aktivierung von Verschlüsselung im Ruhezustand für die etcd-Daten. Neuere Versionen von Kubernetes verwenden etcd3 und haben die Möglichkeit, die native Verschlüsselung von etcd zu aktivieren. Dies ist jedoch ein manueller Prozess, der in der Konfiguration des API-Servers durch die Angabe eines Anbieters und der entsprechenden Schlüsselmedien konfiguriert werden muss, um die in etcd gespeicherten geheimen Daten ordnungsgemäß zu verschlüsseln. Seit Kubernetes v1.10 (in v1.12 wurde es in die Beta-Phase überführt) gibt es den KMS-Anbieter, der einen sichereren Schlüsselprozess verspricht, indem er KMS-Systeme von Drittanbietern nutzt, um die richtigen Schlüssel zu speichern.

Gemeinsame bewährte Methoden für dieConfigMap- und Secrets-APIs

Die meisten Probleme, die bei der Verwendung einer ConfigMap oder eines Geheimnisses auftreten, sind falsche Annahmen darüber, wie Änderungen behandelt werden, wenn die im Objekt enthaltenen Daten aktualisiert werden. Wenn du die Regeln der Straße verstehst und ein paar Tricks anwendest, die es dir erleichtern, diese Regeln einzuhalten, kannst du Ärger aus dem Weg gehen:

  • Um dynamische Änderungen an deiner Anwendung zu unterstützen, ohne neue Versionen der Pods bereitstellen zu müssen, hängst du deine ConfigMaps/Secrets als Volume ein und konfigurierst deine Anwendung mit einem File Watcher, der die geänderten Dateidaten erkennt und sich bei Bedarf neu konfiguriert. Der folgende Code zeigt ein Deployment, das eine ConfigMap und eine Secret-Datei als Volume einbindet:

apiVersion: v1
kind: ConfigMap
metadata:
    name: nginx-http-config
    namespace: myapp-prod
data:
  config: |
    http {
      server {
        location / {
        root /data/html;
        }

        location /images/ {
          root /data;
        }
      }
    }
apiVersion: v1
kind: Secret
metadata:
  name: myapp-api-key
type: Opaque
data:
  myapikey: YWRtd5thSaW4=
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mywebapp
  namespace: myapp-prod
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 8080
    volumeMounts:
    - mountPath: /etc/nginx
      name: nginx-config
    - mountPath: /usr/var/nginx/html/keys
      name: api-key
  volumes:
    - name: nginx-config
      configMap:
        name: nginx-http-config
        items:
        - key: config
          path: nginx.conf
    - name: api-key
      secret:
        name: myapp-api-key
        secretname: myapikey
Hinweis

Bei der Verwendung von volumeMounts gibt es ein paar Dinge zu beachten. Erstens: Sobald die ConfigMap/Secret erstellt ist, füge sie als Volume in der Spezifikation deines Pods hinzu. Hänge dieses Volume dann in das Dateisystem des Containers ein. Jeder Eigenschaftsname in der ConfigMap/Secret wird zu einer neuen Datei im gemounteten Verzeichnis, und der Inhalt jeder Datei ist der in der ConfigMap/Secret angegebene Wert. Zweitens solltest du vermeiden, ConfigMaps/Secrets mit der Eigenschaft volumeMounts.subPath zu mounten. Dadurch wird verhindert, dass die Daten im Volume dynamisch aktualisiert werden, wenn du eine ConfigMap/Secret mit neuen Daten aktualisierst.

  • ConfigMaps/Secrets müssen im Namensraum der Pods, die sie verwenden, vorhanden sein, bevor der Pod deployed wird. Mit dem optionalen Flag kannst du verhindern, dass die Pods nicht starten, wenn die ConfigMap/Secret nicht vorhanden ist.

  • Verwende einen Admission Controller, um bestimmte Konfigurationsdaten sicherzustellen oder um Einsätze zu verhindern, für die keine bestimmten Konfigurationswerte festgelegt sind. Ein Beispiel wäre, wenn du verlangst, dass alle Java-Workloads in Produktionsumgebungen bestimmte JVM-Eigenschaften haben müssen.

  • Wenn du Helm verwendest, um Anwendungen in deiner Umgebung freizugeben, kannst du einen Life Cycle Hook verwenden, um sicherzustellen, dass die ConfigMap/Secret-Vorlage eingesetzt wird, bevor der Einsatz erfolgt.

  • Manche Anwendungen erfordern, dass ihre Konfiguration in einer einzigen Datei wie einer JSON- oder YAML-Datei übertragen wird. ConfigMap/Secret ermöglicht einen ganzen Block von Rohdaten, indem es das Symbol | verwendet, wie hier gezeigt:

apiVersion: v1
kind: ConfigMap
metadata:
  name: config-file
data:
  config: |
    {
      "iotDevice": {
        "name": "remoteValve",
        "username": "CC:22:3D:E3:CE:30",
        "port": 51826,
        "pin": "031-45-154"
      }
    }
  • Wenn die Anwendung Systemumgebungsvariablen verwendet, um ihre Konfiguration zu bestimmen, kannst du die Injektion der ConfigMap-Daten nutzen, um ein Umgebungsvariablen-Mapping im Pod zu erstellen. Dafür gibt es zwei Möglichkeiten: jedes Schlüssel/Wert-Paar in der ConfigMap als eine Reihe von Umgebungsvariablen mit envFrom in den Pod einbinden und dannconfigMapRef oder secretRef verwenden, oder einzelne Schlüssel mit ihren jeweiligen Werten mit configMapKeyRef oder secretKeyRef zuweisen.

  • Wenn du die Methode configMapKeyRef oder secretKeyRef verwendest, musst du beachten, dass der Pod nicht gestartet werden kann, wenn der Schlüssel nicht existiert.

  • Wenn du alle Schlüssel/Wert-Paare aus der ConfigMap/Secret mit envFrom in den Pod lädst, werden alle Schlüssel, die als ungültige Umgebungswerte gelten, übersprungen; der Pod kann jedoch gestartet werden. Das Ereignis für den Pod enthält ein Ereignis mit dem Grund InvalidVariableNamesund der entsprechenden Meldung, welcher Schlüssel übersprungen wurde. Der folgende Code ist ein Beispiel für ein Deployment mit einer ConfigMap und einer Secret-Referenz als Umgebungsvariable:

apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
data:
  mysqldb: myappdb1
  user: mysqluser1
apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
type: Opaque
data:
  rootpassword: YWRtJasdhaW4=
  userpassword: MWYyZDigKJGUyfgKJBmU2N2Rm
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-db-deploy
spec:
  selector:
    matchLabels:
      app: myapp-db
  template:
    metadata:
      labels:
        app: myapp-db
    spec:
      containers:
      - name: myapp-db-instance
        image: mysql
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
        - containerPort: 3306
        env:
          - name: MYSQL_ROOT_PASSWORD
            valueFrom:
              secretKeyRef:
                name: mysql-secret
                key: rootpassword
          - name: MYSQL_PASSWORD
            valueFrom:
              secretKeyRef:
                name: mysql-secret
                key: userpassword
          - name: MYSQL_USER
            valueFrom:
              configMapKeyRef:
                name: mysql-config
                key: user
          - name: MYSQL_DB
            valueFrom:
              configMapKeyRef:
                name: mysql-config
                key: mysqldb
  • Wenn du Befehlszeilenargumente an deine Container weitergeben musst, kannst du die Daten der Umgebungsvariablen mit der Interpolationssyntax $(ENV_KEY) beziehen:

[...]
spec:
  containers:
  - name: load-gen
    image: busybox
    command: ["/bin/sh"]
args: ["-c", "while true; do curl $(WEB_UI_URL); sleep 10;done"]
    ports:
    - containerPort: 8080
    env:
    - name: WEB_UI_URL
      valueFrom:
        configMapKeyRef:
          name: load-gen-config
          key: url
  • Wenn ConfigMap/Secret-Daten als Umgebungsvariablen verwendet werden, ist es sehr wichtig zu wissen, dass Aktualisierungen der Daten in der ConfigMap/Secret nicht im Pod aktualisiert werden und einen Pod-Neustart erfordern. Dies kann entweder durch das Löschen der Pods und die Erstellung eines neuen Pods durch den ReplicaSet-Controller geschehen oder durch das Auslösen einer Deployment-Aktualisierung, die der in der Deployment-Spezifikation angegebenen Aktualisierungsstrategie der Anwendung folgt.

  • Es ist einfacher, davon auszugehen, dass alle Änderungen an einer ConfigMap/Secret eine Aktualisierung des gesamten Deployments erfordern; so wird sichergestellt, dass der Code die neuen Konfigurationsdaten übernimmt, auch wenn du Umgebungsvariablen oder Volumes verwendest. Um dies zu vereinfachen, kannst du eine CI/CD-Pipeline verwenden, um die Eigenschaft name der ConfigMap/Secret zu aktualisieren und auch die Referenz im Deployment zu aktualisieren, was dann eine Aktualisierung des Deployments durch normale Kubernetes-Aktualisierungsstrategien auslöst. Wir werden dies im folgenden Beispielcode untersuchen. Wenn du Helm verwendest, um deinen Anwendungscode in Kubernetes freizugeben, kannst du eine Annotation in der Deployment-Vorlage nutzen, um die sha256 Prüfsumme der ConfigMap/Secret zu überprüfen. Dadurch wird Helm veranlasst, das Deployment mit dem Befehl helm upgrade zu aktualisieren, wenn die Daten in einer ConfigMap/Secret geändert werden:

apiVersion: apps/v1
kind: Deployment
[...]
spec:
  template:
    metadata:
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml")
            . | sha256sum }}
[...]

Bewährte Methoden speziell für Geheimnisse

Da es sich bei der Secrets-API um sensible Daten handelt, gibt es natürlich noch spezifischere bewährte Methoden, die sich hauptsächlich auf die Sicherheit der Daten selbst beziehen:

  • Wenn dein Workload nicht direkt auf die Kubernetes-API zugreifen muss, empfiehlt es sich, das automatische Einhängen der API-Anmeldedaten für das Servicekonto (Standard oder vom Betreiber erstellt) zu blockieren. Dadurch werden die API-Aufrufe an den API-Server reduziert, da eine Watch verwendet wird, um die API-Anmeldedaten zu aktualisieren, wenn die Anmeldedaten ablaufen. In sehr großen Clustern oder Clustern mit vielen Pods werden dadurch die Aufrufe an die Control Plane reduziert und damit eine mögliche Ursache für Leistungseinbußen verringert. Dies kann im ServiceAccount oder in der Pod-Spezifikation selbst festgelegt werden:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: app1-svcacct
automountServiceAccountToken: false
[...]
apiVersion: v1
kind: Pod
metadata:
  name: app1-pod
spec:
  serviceAccountName: app1-svcacct
  automountServiceAccountToken: false
[...]
  • Die ursprüngliche Spezifikation für die Secrets-API sah eine steckbare Architektur vor, damit die tatsächliche Speicherung der Geheimnisse je nach Bedarf konfiguriert werden kann. Lösungen wie HashiCorp Vault, Aqua Security, Twistlock, AWS Secrets Manager, Google Cloud KMS oder Azure Key Vault ermöglichen die Nutzung externer Speicherungen für geheime Daten, die ein höheres Maß an Verschlüsselung und Überprüfbarkeit bieten, als dies in Kubernetes selbst der Fall ist. Das ProjektExternalSecrets Operator der Linux Foundation bietet eine native Möglichkeit, diese Funktionalität bereitzustellen.

  • Weisen Sie ein imagePullSecrets einem serviceaccount zu, das der Pod verwenden wird, um das Geheimnis automatisch zu mounten, ohne es impod.spec deklarieren zu müssen. Du kannst das Standard-Servicekonto für den Namensraum deiner Anwendung ändern und das imagePullSecrets direkt hinzufügen. Dadurch wird es automatisch zu allen Pods in diesem Namensraum hinzugefügt:

Create the docker-registry secret first
kubectl create secret docker-registry registryKey --docker-server
myreg.azurecr.io --docker-username myreg --docker-password $up3r$3cr3tP@ssw0rd
--docker-email ignore@dummy.com

patch the default serviceaccount for the namespace you wish to configure
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name":
"registryKey"}]}'
  • Nutze CI/CD-Funktionen, um während der Release-Pipeline Geheimnisse aus einem sicheren Tresor oder einem verschlüsselten Speicher mit einem Hardware-Sicherheitsmodul (HSM) zu beziehen. Dies ermöglicht eine Aufgabentrennung. Das Sicherheitsmanagementteam kann die Geheimnisse erstellen und verschlüsseln, und die Entwickler müssen lediglich die Namen der erwarteten Geheimnisse referenzieren. Dies ist auch der bevorzugte DevOps-Prozess, um eine dynamischere Anwendungsbereitstellung zu gewährleisten.

RBAC

Bei der Arbeit in großen, verteilten Umgebungen ist es sehr üblich, dass eine Art von Sicherheitsmechanismus benötigt wird, um unbefugten Zugriff auf kritische Systeme zu verhindern. Es gibt zahlreiche Strategien, um den Zugriff auf Ressourcen in Computersystemen zu begrenzen, aber die meisten durchlaufen die gleichen Phasen. Eine Analogie zu einer alltäglichen Erfahrung wie einem Flug in ein fremdes Land kann helfen, die Prozesse zu erklären, die in Systemen wie Kubernetes ablaufen. Wir können die Erfahrung eines gewöhnlichen Reisenden mit einem Reisepass, einem Reisevisum und Zoll- oder Grenzbeamten nutzen, um den Prozess zu veranschaulichen:

Reisepass (Thema Authentifizierung)

Normalerweise brauchst du einen Reisepass, der von einer Behörde ausgestellt wird und mit dem du nachweisen kannst, wer du bist. Dies entspricht einem Benutzerkonto in Kubernetes. Kubernetes verlässt sich bei der Authentifizierung von Nutzern auf eine externe Behörde; Dienstkonten sind jedoch eine Art von Konto, das direkt von Kubernetes verwaltet wird.

Visum oder Reiserichtlinie (Genehmigung)

Die Länder haben formelle Vereinbarungen, um Reisende mit Reisepässen aus anderen Ländern durch formelle kurzfristige Vereinbarungen wie Visa zu akzeptieren. In den Visa wird auch festgelegt, was der Besucher tun darf und wie lange er sich im Gastland aufhalten darf, je nach Art des Visums. Dies entspricht der Autorisierung in Kubernetes. Kubernetes hat verschiedene Autorisierungsmethoden, aber RBAC ist die am häufigsten verwendete. Dies ermöglicht einen sehr granularen Zugriff auf verschiedene API-Funktionen.

Grenzschutz oder Zoll (Einlasskontrolle)

Bei der Einreise in ein fremdes Land gibt es in der Regel eine Behörde, die die erforderlichen Dokumente, einschließlich Pass und Visum, überprüft und in vielen Fällen auch kontrolliert, was in das Land gebracht wird, um sicherzustellen, dass es den Gesetzen des Landes entspricht. In Kubernetes entspricht dies den Admission Controllern. Zulassungssteuerungen können Anfragen an die API auf der Grundlage definierter Regeln und Richtlinien zulassen, verweigern oder ändern. Kubernetes verfügt über viele integrierte Zulassungssteuerungen wiePodSecurity, ResourceQuota und ServiceAccount. Kubernetes ermöglicht auch dynamische Controller durch die Verwendung von validierenden oder mutierenden Admission Controllern.

Der Schwerpunkt dieses Abschnitts liegt auf dem am wenigsten verstandenen und am meisten gemiedenen dieser drei Bereiche: RBAC. Bevor wir einige der bewährten Methoden vorstellen, brauchen wir eine Einführung in das RBAC-System von Kubernetes.

RBAC-Fibel

Der RBAC-Prozess in Kubernetes hat drei Hauptkomponenten, die definiert werden müssen: das Subjekt, die Regel und die Rollenbindung.

Themen

Die erste Komponente von ist das Subjekt, also das Objekt, das auf Zugriff geprüft wird. Das Subjekt ist normalerweise ein Benutzer, ein Dienstkonto oder eine Gruppe. Wie bereits erwähnt, werden sowohl Benutzer als auch Gruppen außerhalb von Kubernetes durch das verwendete Autorisierungsmodul verwaltet. Wir können diese als Basisauthentifizierung, x.509-Client-Zertifikate oder Inhaber-Token kategorisieren. Die gängigsten Implementierungen verwenden entweder x.509-Client-Zertifikate oder eine Art von Inhaber-Token unter Verwendung eines OpenID Connect-Systems wie Azure Active Directory (Azure AD), Salesforce oder Google.

Hinweis

Dienstkonten in Kubernetes unterscheiden sich von Benutzerkonten dadurch, dass sie an einen Namensraum gebunden sind und intern in Kubernetes gespeichert werden; sie sollen Prozesse und keine Personen darstellen und werden von nativen Kubernetes-Controllern verwaltet.

Regeln

Einfach ausgedrückt: ist die Liste der Aktionen, die für ein bestimmtes Objekt (Ressource) oder eine Gruppe von Objekten in der API ausgeführt werden können. Die Verben entsprechen den typischen CRUD-Vorgängen (Erstellen, Lesen, Aktualisieren und Löschen), allerdings mit einigen zusätzlichen Funktionen in Kubernetes wie watch, list undexec. Die Objekte orientieren sich an den verschiedenen API-Komponenten und sind in Kategorien zusammengefasst. Pod-Objekte zum Beispiel gehören zur Kern-API und können mit apiGroup: "" referenziert werden, während Deployments unter die App-API-Gruppe fallen. Das ist die eigentliche Stärke des RBAC-Prozesses und wahrscheinlich das, was die Leute einschüchtert und verwirrt, wenn sie richtige RBAC-Kontrollen erstellen.

Rollen

Rollen ermöglichen die Definition des Geltungsbereichs der definierten Regeln. In Kubernetes gibt es zwei Arten von Rollen, role und clusterRole, mit dem Unterschied, dassrole spezifisch für einen Namensraum ist und clusterRole eine clusterweite Rolle für alle Namensräume ist. Ein Beispiel für eine Rollendefinition mit Namespace-Geltungsbereich wäre wie folgt:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: pod-viewer
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

RoleBindings

Die RoleBinding ermöglicht die Zuordnung eines Subjekts wie eines Benutzers oder einer Gruppe zu einer bestimmten Rolle. Bindungen haben außerdem zwei Modi: roleBinding Der Modus "RoleBinding" ist spezifisch für einen Namensraum und der Modus " clusterRoleBinding" gilt für den gesamten Cluster. Hier ist ein Beispiel für eine RoleBinding mit dem Namespace :

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: noc-helpdesk-view
  namespace: default
subjects:
- kind: User
  name: helpdeskuser@example.com
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role #this must be Role or ClusterRole
  name: pod-viewer # this must match the name of the Role or ClusterRole
                   # to bind to
  apiGroup: rbac.authorization.k8s.io

Bewährte Methoden für RBAC

RBAC ist eine wichtige Komponente für den Betrieb einer sicheren, zuverlässigen und stabilen Kubernetes-Umgebung. Die Konzepte, die RBAC zugrunde liegen, können sehr komplex sein. Wenn du dich jedoch an einige bewährte Methoden hältst, kannst du einige der größten Stolpersteine aus dem Weg räumen:

  • Anwendungen, die für die Ausführung in Kubernetes entwickelt werden, benötigen selten eine RBAC-Rolle und eine damit verbundene Rollenbindung. Nur wenn der Anwendungscode direkt mit der Kubernetes-API interagiert, benötigt die Anwendung eineRBAC-Konfiguration.

  • Wenn die Anwendung direkt auf die Kubernetes-API zugreifen muss, um vielleicht die Konfiguration zu ändern, wenn Endpunkte zu einem Dienst hinzugefügt werden, oder wenn sie alle Pods in einem bestimmten Namensraum auflisten muss, ist es die bewährte Methode, ein neues Dienstkonto zu erstellen, das dann in der Pod-Spezifikation angegeben wird. Dann erstellst du eine Rolle, die so wenig Privilegien wie möglich hat, um ihr Ziel zu erreichen.

  • Nutze einen OpenID Connect-Dienst, der Identitätsmanagement und bei Bedarf eine Zwei-Faktor-Authentifizierung ermöglicht. Dies ermöglicht eine höhere Stufe der Identitätsauthentifizierung. Weisen Sie Benutzergruppen Rollen zu, die die geringsten Privilegien haben, die für die Ausführung der Aufgabe erforderlich sind.

  • Zusätzlich zu den oben genannten Praktiken solltest du Just-in-Time-Zugangssysteme (JIT) verwenden, um Site Reliability Engineers (SREs), Operatoren und anderen Personen, die für einen kurzen Zeitraum erweiterte Rechte benötigen, um eine ganz bestimmte Aufgabe zu erledigen, Zugang zu gewähren. Alternativ sollten diese Nutzer/innen andere Identitäten haben, die bei der Anmeldung stärker geprüft werden, und diesen Konten sollten von dem Benutzerkonto oder der Gruppe, die an eine Rolle gebunden ist, höhere Rechte zugewiesen werden.

  • Für CI/CD-Tools, die in deinen Kubernetes-Clustern eingesetzt werden, sollten spezielle Dienstkonten verwendet werden. Dies gewährleistet die Nachvollziehbarkeit innerhalb des Clusters und gibt Aufschluss darüber, wer möglicherweise Objekte in einem Cluster bereitgestellt oder gelöscht hat.

  • Wenn du noch Helm v2 für die Bereitstellung von Anwendungen verwendest, ist das Standard-Servicekonto Tiller, das auf kube-system bereitgestellt wird. Es ist besser, Tiller in jedem Namensraum mit einem Servicekonto speziell für Tiller bereitzustellen, das für diesen Namensraum skaliert ist. In dem CI/CD-Tool, das den Helm-Installations-/Upgrade-Befehl aufruft, initialisierst du den Helm-Client mit dem Servicekonto und dem spezifischen Namensraum für das Deployment. Der Name des Servicekontos kann für jeden Namensraum gleich sein, aber der Namensraum sollte spezifisch sein. Es ist ratsam, auf Helm v3 umzusteigen, da eines der Kernprinzipien darin besteht, dass Tiller nicht mehr für den Betrieb in einem Cluster benötigt wird. Die neue Architektur ist vollständig clientbasiert und nutzt den RBAC-Zugriff des Benutzers, der die Helm-Befehle aufruft. Dies entspricht dem bevorzugten Ansatz der clientbasierten Werkzeuge für die Kubernetes-API.

  • Beschränke alle Anwendungen, die watch und list benötigen, auf die Secrets API. Dadurch kann die Anwendung oder die Person, die den Pod bereitgestellt hat, die Geheimnisse in diesem Namensraum einsehen. Wenn eine Anwendung für bestimmte Geheimnisse auf die Secrets-API zugreifen muss, beschränke die Verwendung von get auf bestimmte Geheimnisse, die die Anwendung lesen muss, außer denen, die ihr direkt zugewiesen sind.

Zusammenfassung

Die Grundsätze für die Entwicklung von Anwendungen für die native Bereitstellung in der Cloud sind ein Thema für einen anderen Tag, aber es ist allgemein anerkannt, dass die strikte Trennung von Konfiguration und Code ein Schlüsselprinzip für den Erfolg ist. Mit nativen Objekten für unsensible Daten, der ConfigMap-API, und für sensible Daten, der Secrets-API, kann Kubernetes diesen Prozess nun in einem deklarativen Ansatz verwalten. Da immer mehr kritische Daten nativ in der Kubernetes-API dargestellt und gespeichert werden, ist es wichtig, den Zugang zu diesen APIs durch geeignete Gated Security-Prozesse wie RBAC und integrierte Authentifizierungssysteme zu sichern.

Wie du im weiteren Verlauf dieses Buches sehen wirst, durchdringen diese Prinzipien jeden Aspekt der richtigen Bereitstellung von Diensten in einer Kubernetes-Plattform, um ein stabiles, zuverlässiges, sicheres und robustes System aufzubauen.

Get Kubernetes Best Practices, 2. Auflage now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.