Access Control
Ziel
In diesem Projekt geht es um Zugriffskontrolle und wer welche Aktionen an einem Cluster durchführen darf. Sie werden:
- Namespaces verwenden
 - RBAC verwenden
 
Hilfsmittel
- Versuchen Sie, die unten stehenden Aufgaben mit Hilfe der Folien und der Cheatsheets eigenständig zu lösen.
 - Sollten Sie dabei Probleme haben, finden Sie bei jeder Aufgabe einen ausklappbaren Block, in dem der Lösungsweg beschrieben wird.
 
Aufgabe 1: Namespaces
Aufgabe 1.1: Namespaces im Cluster untersuchen
- Verwenden Sie 
kubectl get namespace, um einen Überblick über die Namespaces im Cluster zu erhalten 
Aufgabe 1.2: Namespaces erstellen
- Erstellen Sie die Datei 
namespace.yamlmit einem Namespacetest 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
---
apiVersion: v1
kind: Namespace
metadata:
  name: test
- Deployen Sie den Namespace
 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f namespace.yaml
- Erstellen Sie ein Deployment in dem Namespace 
testmit dem Namennginxund dem Imagenginx 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl create deployment nginx --image=nginx --namespace=test
- Verwenden Sie 
kubectl get podsum die Pods im Namespacetestzu erhalten 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl get pods --namespace=test
Aufgabe 1.3: Namespaces verstehen
Namespaces bieten Separierung und keine Isolation. Das werden wir in dieser Aufgabe anschauen.
- Erstellen Sie einen Namespace 
devmit einer YAML-Dateidev.yaml 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
---
apiVersion: v1
kind: Namespace
metadata:
  name: dev
- Deployen Sie das Namespace-Manifest.
 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f dev.yaml
- Erstellen Sie ein nginx Deployment im 
devNamespace sowie einen Service mit einer YAML-Dateinginx-dev.yamlund folgendem Inhalt: 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: dev
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      volumes:
      - name: data
        emptyDir: {}
      initContainers:
      - name: init
        image: nginx
        command:
        - bash
        - -c
        args:
        - |
          echo "Overriding index.html file..." && echo "Hello from DEV-namespace" | tee /usr/share/nginx/html/index.html
        volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: data
      containers:
      - name: nginx
        image: nginx
        volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: data
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: dev
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
- Deployen Sie das Deployment und Service Manifest
 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f nginx-dev.yaml
- Erstellen Sie einen Namespace 
prodmit einer YAML-Dateiprod.yaml 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
---
apiVersion: v1
kind: Namespace
metadata:
  name: prod
- Deployen Sie das Namespace Manifest
 - Erstellen Sie ein nginx Deployment im 
prodNamespace sowie einen Service mit einer YAML-Dateinginx-prod.yamlund folgendem Inhalt: 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: prod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      volumes:
      - name: data
        emptyDir: {}
      initContainers:
      - name: init
        image: nginx
        command:
        - bash
        - -c
        args:
        - |
          echo "Overriding index.html file..." && echo "Hello from PROD-namespace" | tee /usr/share/nginx/html/index.html
        volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: data
      containers:
      - name: nginx
        image: nginx
        volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: data
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: prod
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
- Deployen Sie das Deployment und Service Manifest
 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f nginx-prod.yaml
- Führen Sie ein 
execin dasdevDeployment aus und versuchen Sie auf dasprodDeployment zuzugreifen 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl --namespace dev exec services/nginx -- curl http://nginx
kubectl --namespace dev exec services/nginx -- curl http://nginx.dev
kubectl --namespace dev exec services/nginx -- curl http://nginx.prod
Wie Sie sehen können, kann das dev Deployment auf das prod Deployment
zugreifen. Das liegt daran, dass Namespaces eine Möglichkeit bieten, Ressourcen
in einem Kubernetes-Cluster zu organisieren. Sie sind für den Einsatz in
Umgebungen mit vielen Benutzern in mehreren Teams oder Projekten gedacht, bieten
aber keine Netzwerkisolation. Wenn Sie die dev und prod Deployments
isolieren möchten, müssen Sie Netzwerkrichtlinien verwenden.
Aufgabe 2: Kubeconfig
Aufgabe 2.1: Aktuelle Config untersuchen
- Verwenden Sie 
kubectl config viewum die aktuelle Kubeconfig anzuzeigen 
Die Kubeconfig enthält Informationen über Cluster, Kontexte und Benutzer.
Ein cluster enthält einen Namen, ein Zertifikat und die Adresse des API-Endpunkts.
Ein user enthält den Benutzernamen und das Token zur Authentifizierung.
Ein context ist eine benannte Referenz, der Zugriffsparameter wie Cluster,
Benutzer und Namespace unter einem Namen gruppiert.
Der Context bietet die Möglichkeit, um schnell und einfach zwischen Clustern,
Namespaces und Benutzern durch current-context zu wechseln.
Aufgabe 2.2: Speicherort der Kubeconfig untersuchen
- Schauen Sie sich den Wert der Umgebungsvariable 
$KUBECONFIGan. Diese Variable enthält den Pfad, an dem die Kubeconfig gespeichert ist. - Verwenden Sie 
kubectl --kubeconfig=/home/coder/.kube/kubeconfig config viewum den Kubeconfig-Pfad explizit zu setzen. - Verwenden Sie 
kubectl --kubeconfig=/home/coder/.kube/nonexisting_file config viewum zu sehen, wie eine leere Config aussehen würde. 
Aufgabe 2.3: Übersicht der Config Subcommands
- Verwenden Sie 
kubectl configum eine Übersicht der verfügbaren Subcommands für die Nutzung von Kubeconfig zu erhalten 
Aufgabe 2.4: Context lesen
- Verwenden Sie 
kubectl config get-contextsum alle verfügbaren Contexts anzuzeigen - Verwenden Sie 
kubectl config current-contextum den aktuell verwendeten Context anzuzeigen 
Aufgabe 2.5: Kubeconfig sichern
- 
Kopieren Sie die Kubeconfig-Datei
cp ~/.kube/kubeconfig ~/.kube/kubeconfig.bak 
Wir werden in den folgenden Aufgaben Änderungen an der Kubeconfig-Datei vornehmen. Sollten Sie Fehler machen, können Sie die Sicherungskopie wiederherstellen.
Aufgabe 2.6: Context hinzugefügt und löschen
- Verwenden Sie 
kubectl config set-contextum den Namespace des aktuellen Contexts aufkube-systemzu setzen 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl config set-context --current --namespace=kube-system --user=code-x-cluster-admin
- Verwenden Sie 
kubectl config get-contextsum den aktuellen Context zu überprüfen - 
Führen Sie
kubectl get podsaus, um zu sehen, dass der Namespace aufkube-systemgesetzt wurde - 
Setzen Sie für einen Context den Namespace auf
default, nutzen Sie dabei den Context-Namen 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl config set contexts.code-x-admin.namespace default
- Überprüfen Sie den Namespace des Contexts
 - Löschen Sie den Namespace aus einem Context mit 
kubectl config unset 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl config unset contexts.code-x-admin.namespace
Aufgabe 2.7: Neuen Context erstellen
- Erstellen Sie einen neuen Context mit dem Namen 
my-system-context, der folgende Eigenschaften hat: - Cluster: 
code-N(Ersetzen Siecode-Ndurch den Namen Ihres Clusters) - Namespace: 
kube-system - User: 
code-x-cluster-admin(Ersetzen Siecode-Ndurch den Namen Ihres Clusters) 
Hint
- Die Workshop-Umgebung bietet nur einen einzigen Cluster und Benutzer
 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl config set-context my-system-context --cluster=code-1 --namespace=kube-system --user=code-x-cluster-admin
- Überprüfen Sie den neuen Context 
my-system-context 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl config get-contexts my-system-context
Aufgabe 2.8: Context Eigenschaften auslesen
- Verwenden Sie 
kubectl config viewum die gesamte Kubeconfig anzuzeigen - Lassen Sie sich die die Config als JSON anzeigen und filtern Sie nach der Server Adresse (
.cluster.server) 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl config view -o json | jq -r '.clusters[] | select(.name | startswith("code-")) | .cluster.server'
Aufgabe 2.9: Kubeconfig Backup wiederherstellen
- Stellen Sie die Sicherungskopie der Kubeconfig-Datei wieder her:
 
cp ~/.kube/kubeconfig.bak ~/.kube/kubeconfig
Backup
Sollten Sie vergesen haben ein Backup der Kubeconfig zu erstellen, können Sie die Kubeconfig auch wiefolgt wieder herstellen:
cat /mnt/secret/kubeconfig > /home/coder/.kube/kubeconfig
Aufgabe 3: Role Based Access Control (RBAC) (Optional)
Aufgabe 3.1: Namespace erstellen
- Erstellen Sie einen Namespace 
appmit einer YAML-Dateiapp-namespace.yaml 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
---
apiVersion: v1
kind: Namespace
metadata:
  name: app
- Deployen Sie das Namespace Manifest
 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f app-namespace.yaml
Aufgabe 3.2: ServiceAccount erstellen
- Erstellen Sie einen ServiceAccount mit dem Namen 
bobim Namespaceappin der Dateibob.yaml 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: bob
  namespace: app
- Deployen Sie den ServiceAccount
 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f bob.yaml
- Schauen Sie sich den ServiceAccount mit 
kubectl get serviceaccountsim Namespaceappan 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl --namespace app get serviceaccounts
Aufgabe 3.3: Rolle erstellen
- Erstellen Sie eine Rolle mit dem Namen 
pod-adminim Namespaceappmit der folgenden Regel: 
apiGroups: [""] # "" indicates the core API group which covers Pod resources
resources: ["pods"]
verbs:
- "create"
- "get"
- "list"
- "watch"
- "delete"
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-admin
  namespace: app
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs:
  - "create"
  - "get"
  - "list"
  - "watch"
  - "delete"
- Deployen Sie die Rolle
 
Die Rolle pod-admin erlaubt es, Pods zu erstellen, anzuzeigen und zu
löschen, jedoch nur im Namespace app, in dem die Rolle erstellt wurde.
- Schauen Sie sich die Rollen im Namespace 
appan 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl --namespace app get roles
Aufgabe 3.4: RoleBinding erstellen
- Erstellen Sie ein RoleBinding mit dem Namen 
pod-adminsim Namespaceapp. Das RoleBinding sollte die Berechtigungen der Rollepod-admindem ServiceAccountbobgewähren. 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-admins
  namespace: app
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: pod-admin
subjects:
- kind: ServiceAccount
  name: bob
  namespace: app
- Deployen Sie das RoleBinding
 - Schauen Sie sich die RoleBindings im Namespace 
appan 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl --namespace app get rolebindings
Aufgabe 3.5: Impersonation
- Erstellen Sie einen Pod als 
bobmit dem Namennginxim Namespaceappmit dem Imagenginx. Um sich als ServiceAccountbobzu authentifizieren, verwenden Sie die Option--as system:serviceaccount:app:bobmitkubectlSie können folgendes Manifest verwenden: 
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: app
spec:
  containers:
  - name: nginx
    image: nginx
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f pod.yaml --as system:serviceaccount:app:bob
- Schauen Sie sich den Pod im Namespace 
appalsboban 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl get pods --namespace app --as system:serviceaccount:app:bob
Aufgabe 3.6: Impersonation mit unzureichenden Berechtigungen
- Versuchen Sie, die Ressourcen aus dem 
defaultNamespace mit dem ServiceAccountbobaufzulisten 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl get pods --namespace default --as system:serviceaccount:app:bob
Aufgabe 4: Cluster Authentifizierung (Optional)
- Setzen Sie den Namespace in der Kubeconfig auf 
default 
kubectl config set-context --current --namespace=default
Aufgabe 4.1: Pod erstellen
- Erstellen Sie einen Pod mit dem folgen Manifest:
 
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
- Deployen Sie den Pod
 
Aufgabe 4.2: ServiceAccount erstellen
- Erstellen Sie einen ServiceAccount mit dem Namen 
alice 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: alice
- Deployen Sie den ServiceAccount
 - Lassen Sie sich die ServiceAccounts mit 
kubectl get serviceaccountsanzeigen 
Aufgabe 4.3: Secret für ServiceAccount erstellen
- Erstellen Sie ein Secret vom Typ 
kubernetes.io/service-account-tokenmit dem Namenalice 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
---
apiVersion: v1
kind: Secret
metadata:
  name: alice-credentials
  annotations:
    kubernetes.io/service-account.name: alice
type: kubernetes.io/service-account-token
- Lassen Sie sich das secret mit 
kubectl get secret <secret>anzeigen - Lassen Sie sich die Details des Secrets als YAML anzeigen
 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl get secret alice-credentials -o yaml
Aufgabe 4.4: JWT aus dem Secret lesen
- Lesen Sie den 
data.tokenAbschnitt aus dem Secret und nutzen Siebase64 -dum ihn zu dekodieren 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl get secret alice-credentials -o json | jq -r '.data.token' | base64 -d
JWT Struktur
JWT-Tokens bestehen aus drei Teilen: Header, Payload und Signatur
Jeder Bestandteil ist separat base64 kodiert. Die Bestandteile werden durch Punkten . verbunden.
Die Signatur eines JWT wird verwendet, um zu überprüfen, dass der Inhalt des
JWT gültig und vertrauenswürdig ist. Manipulation des Payloads oder Headers
würde die Signatur brechen.
- Beachten Sie die Punkte 
.als Trennzeichen der JWT Teile 
Aufgabe 4.5: JWT dekodieren
- Nutzen Sie das 
jwtKommandozeilenwerkzeug, um den JWT aus Aufgabe 3 zu dekodieren. 
kubectl get secret alice-credentials -o json | jq -r '.data.token' | base64 -d | jwt decode -
Sie sehen den Header und die Payload (Claims) des JWT, der Signaturteil überprüft aber nicht angezeigt.
Wir können ablesen, dass das Token den ServiceAccount
alice mit dem Secret alice-credentials im Namespace default
authentifiziert oder kurz: system:serviceaccount:default:alice.
Aufgabe 4.6: Neuen Kubeconfig-Context erstellen
- Nutzen Sie 
kubectl config set-credentialsum einen User Abschnitt zur Kubeconfig Datei mit dem Namenalicehinzuzufügen. Nutzen Sie das JWT als Wert für das User Token. 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
JWT=$(kubectl get secret alice-credentials -o json | jq -r '.data.token' | base64 -d)
kubectl config set-credentials alice --token=${JWT}
- Nutzen Sie 
kubectl config set-contextum einen Context Abschnitt mit dem Namenalicezur Kubeconfig hinzuzufügen: 
CURRENT_CONTEXT=$(kubectl config current-context)
CURRENT_CLUSTER=$(kubectl config view | yq ".contexts[] | select(.name==\"$CURRENT_CONTEXT\") | .context.cluster")
kubectl config set-context alice --cluster=${CURRENT_CLUSTER} --user=alice --namespace=default
- Nutzen Sie 
kubectl config get-contextsum zu überprüfen, ob User und Context hinzugefügt wurden 
Aufgabe 4.7: Neuen Kubeconfig-Context testen
- Wechseln Sie den Kubeconfig-Context zu 
aliceund testen Sie den neuen Context. Nutzen Sie die Option--context=alicemit demkubectl get podsBefehl. 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl --context=alice get pods
Default permissions
Der ServiceAccount "alice" hat noch keine Rollen oder RoleBindings.
Standardmäßig hat ein ServiceAccount keine Berechtigungen. Daher wird kubectl API-Anfragen ablehnen.
Aufgabe 4.8: Rolle und RoleBinding erstellen
- Erstellen Sie eine Rolle mit dem Namen 
pod-adminim Namespacedefaultmit der folgenden Regel: 
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-admin
  namespace: default
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs:
  - "create"
  - "get"
  - "list"
  - "watch"
  - "delete"
- Deployen Sie die Rolle
 - Erstellen Sie ein RoleBinding mit dem Namen 
pod-adminsim Namespacedefault. Das RoleBinding sollte die Berechtigungen der Rollepod-admindem ServiceAccountalicegewähren. 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-admins
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: pod-admin
subjects:
- kind: ServiceAccount
  name: alice
  namespace: default
- Deployen Sie das RoleBinding
 
Aufgabe 4.9: Testen der Berechtigungen
- Testen Sie die Berechtigungen, indem Sie die Pods mit dem neuen Context auflisten
 
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl --context=alice get pods
Sie sollten nun die Pods im Namespace default sehen können.
Cleanup
Löschen Sie alle Objekte die Sie in diesem Hands-On erstellt haben.