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.yaml
mit 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
test
mit dem Namennginx
und 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 pods
um die Pods im Namespacetest
zu 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
dev
mit 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
dev
Namespace sowie einen Service mit einer YAML-Dateinginx-dev.yaml
und 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
prod
mit 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
prod
Namespace sowie einen Service mit einer YAML-Dateinginx-prod.yaml
und 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
exec
in dasdev
Deployment aus und versuchen Sie auf dasprod
Deployment 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 view
um 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
$KUBECONFIG
an. Diese Variable enthält den Pfad, an dem die Kubeconfig gespeichert ist. - Verwenden Sie
kubectl --kubeconfig=/home/coder/.kube/kubeconfig config view
um den Kubeconfig-Pfad explizit zu setzen. - Verwenden Sie
kubectl --kubeconfig=/home/coder/.kube/nonexisting_file config view
um zu sehen, wie eine leere Config aussehen würde.
Aufgabe 2.3: Übersicht der Config Subcommands
- Verwenden Sie
kubectl config
um eine Übersicht der verfügbaren Subcommands für die Nutzung von Kubeconfig zu erhalten
Aufgabe 2.4: Context lesen
- Verwenden Sie
kubectl config get-contexts
um alle verfügbaren Contexts anzuzeigen - Verwenden Sie
kubectl config current-context
um 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-context
um den Namespace des aktuellen Contexts aufkube-system
zu 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-contexts
um den aktuellen Context zu überprüfen -
Führen Sie
kubectl get pods
aus, um zu sehen, dass der Namespace aufkube-system
gesetzt 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-N
durch den Namen Ihres Clusters) - Namespace:
kube-system
- User:
code-x-cluster-admin
(Ersetzen Siecode-N
durch 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 view
um 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
Aufgabe 3: Role Based Access Control (RBAC) (Optional)
Aufgabe 3.1: Namespace erstellen
- Erstellen Sie einen Namespace
app
mit 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
bob
im Namespaceapp
in 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 serviceaccounts
im Namespaceapp
an
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-admin
im Namespaceapp
mit 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
app
an
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-admins
im Namespaceapp
. Das RoleBinding sollte die Berechtigungen der Rollepod-admin
dem ServiceAccountbob
gewä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
app
an
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
bob
mit dem Namennginx
im Namespaceapp
mit dem Imagenginx
. Um sich als ServiceAccountbob
zu authentifizieren, verwenden Sie die Option--as system:serviceaccount:app:bob
mitkubectl
Sie 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
app
alsbob
an
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
default
Namespace mit dem ServiceAccountbob
aufzulisten
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 serviceaccounts
anzeigen
Aufgabe 4.3: Secret für ServiceAccount erstellen
- Erstellen Sie ein Secret vom Typ
kubernetes.io/service-account-token
mit 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.token
Abschnitt aus dem Secret und nutzen Siebase64 -d
um 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
jwt
Kommandozeilenwerkzeug, 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-credentials
um einen User Abschnitt zur Kubeconfig Datei mit dem Namenalice
hinzuzufü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-context
um einen Context Abschnitt mit dem Namenalice
zur 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-contexts
um zu überprüfen, ob User und Context hinzugefügt wurden
Aufgabe 4.7: Neuen Kubeconfig-Context testen
- Wechseln Sie den Kubeconfig-Context zu
alice
und testen Sie den neuen Context. Nutzen Sie die Option--context=alice
mit demkubectl get pods
Befehl.
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-admin
im Namespacedefault
mit 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-admins
im Namespacedefault
. Das RoleBinding sollte die Berechtigungen der Rollepod-admin
dem ServiceAccountalice
gewä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.