· Kubernetes  · 8 Min. Lesezeit

Schluss mit ewigen kubeconfigs: kurzlebige Cluster-Logins mit Pinniped

Statische kubeconfig-Dateien mit langlebigen Tokens laufen nie ab. Pinniped hängt den Cluster-Login an den zentralen Identity-Provider und stellt nur kurzlebige Credentials aus. Einrichtung von Supervisor, Concierge und CLI in v0.47.0, mit Prüfbefehl nach jedem Schritt.

Statische kubeconfig-Dateien mit langlebigen Tokens laufen nie ab. Pinniped hängt den Cluster-Login an den zentralen Identity-Provider und stellt nur kurzlebige Credentials aus. Einrichtung von Supervisor, Concierge und CLI in v0.47.0, mit Prüfbefehl nach jedem Schritt.

Der unscheinbarste Dauerläufer im Kubernetes-Alltag ist die kubeconfig-Datei. Enthält sie ein statisches Token, läuft sie nicht von selbst ab, und sie ist beliebig kopierbar. Wer das Team verlässt, dessen Zugang bleibt bestehen.

Pinniped setzt genau hier an. Die Anmeldung läuft über den zentralen Identity-Provider, und der Cluster sieht nur noch eine Credential mit sehr kurzer Lebensdauer. Dieser Beitrag zeigt die Einrichtung in Version v0.47.0, erschienen am 8. Juli 2026, mit einem Prüfbefehl nach jedem Schritt.

Wann sich der Aufwand lohnt

Pinniped ist kein Werkzeug für einen einzelnen Cluster mit drei Administratoren. Es lohnt sich, wenn mehrere Cluster von denselben Personen bedient werden und ein Identity-Provider existiert, an dem Ein- und Austritte gepflegt werden.

Pinniped macht ausschließlich Authentifizierung. Wer was darf, bleibt Sache von Kubernetes-RBAC. Pinniped liefert Benutzername und Gruppen, die Rechtevergabe passiert über Role- und ClusterRoleBindings.

Die zwei Strategien des Concierge

Entscheiden Sie vor der Installation, wie der Concierge die Credential erzeugt. Die Architektur-Dokumentation beschreibt zwei Wege.

KriteriumKube-Cluster-Signing-CertificateImpersonation Proxy
Signatur der CredentialSigning-Key des Kubernetes-API-Serverseigener Pinniped-Key
Weg zum API-Serverdirektüber einen Proxy mit Identität und Gruppen des Nutzers
Voraussetzungeigener Pod auf dem Node des kube-controller-managerläuft auf jedem Cluster
Typische Umgebungselbst betrieben, etwa kubeadm, kind, TKGManaged Services wie EKS, GKE, AKS
--anonymous-auth=falsenicht möglich, siehe Stolperstein 3zulässig

Die Übersicht der unterstützten Cluster nennt die Details je Distribution.

Voraussetzungen

Beide Komponenten brauchen Linux-Nodes mit amd64 oder arm64:

kubectl get nodes -o custom-columns=NAME:.metadata.name,ARCH:.status.nodeInfo.architecture

Der Supervisor braucht zusätzlich HTTPS-Ingress oder LoadBalancer, denn der Browser des Nutzers muss ihn erreichen. Hier läuft er auf einem Management-Cluster und der Concierge auf dem Workload-Cluster, denn ein Supervisor bedient viele Concierge.

Schritt 1: Die CLI installieren

Die CLI ist ein kubectl-Plugin. Unter macOS und Linux geht der Weg über brew install vmware/pinniped/pinniped-cli, für Linux auf amd64 über den direkten Dreisatz:

curl -Lso pinniped https://get.pinniped.dev/v0.47.0/pinniped-cli-linux-amd64 && chmod +x pinniped && sudo mv pinniped /usr/local/bin/pinniped

Prüfung: pinniped version muss die Version ausgeben. Sonst liegt die Binärdatei nicht im PATH oder ist nicht ausführbar.

Schritt 2: Den Concierge im Workload-Cluster installieren

Erst die CustomResourceDefinitions, dann die übrigen Ressourcen:

kubectl apply -f https://get.pinniped.dev/v0.47.0/install-pinniped-concierge-crds.yaml
kubectl apply -f https://get.pinniped.dev/v0.47.0/install-pinniped-concierge-resources.yaml

Prüfung:

kubectl get pods -n pinniped-concierge
kubectl get credentialissuer -o yaml

Im status.strategies des CredentialIssuer steht, welche der beiden Strategien Erfolg meldet. Diese Antwort kommt aus dem Cluster statt aus einer Vermutung.

Schritt 3: Den Supervisor installieren und erreichbar machen

Der Supervisor kommt mit einem einzigen Manifest:

kubectl apply -f https://get.pinniped.dev/v0.47.0/install-pinniped-supervisor.yaml

Einen von außen erreichbaren Service legen die Manifeste nicht an. Sie brauchen einen eigenen auf targetPort 8443, die Supervisor-Konfiguration nennt diese Form:

apiVersion: v1
kind: Service
metadata:
  name: pinniped-supervisor-loadbalancer
  namespace: pinniped-supervisor
spec:
  type: LoadBalancer
  selector:
    app: pinniped-supervisor
  ports:
    - protocol: TCP
      port: 443
      targetPort: 8443

Den mitgelieferten Service pinniped-supervisor-api auf Port 10250 fassen Sie nicht an, er dient einem anderen Zweck.

Prüfung: Pods kontrollieren, die vergebene Adresse auslesen und im DNS auf supervisor.lab.rz.jabi-it.de zeigen lassen.

kubectl get pods -n pinniped-supervisor
kubectl get service pinniped-supervisor-loadbalancer \
  -o jsonpath="{.status.loadBalancer.ingress[*].ip}" -n pinniped-supervisor

Weil der Supervisor die Authentifizierung aller angeschlossenen Cluster kontrolliert, muss der Zugriff auf seine Interna abgesichert werden. Das ist Stolperstein 1.

Schritt 4: Die FederationDomain anlegen

Die FederationDomain trägt Issuer, TLS-Secret und die Liste der Identity-Provider. Zuerst das Zertifikat als Secret vom Typ kubernetes.io/tls:

kubectl create secret tls supervisor-tls-cert -n pinniped-supervisor \
  --cert tls.crt --key tls.key

Dann die Ressource selbst:

apiVersion: config.supervisor.pinniped.dev/v1alpha1
kind: FederationDomain
metadata:
  name: rz-federation-domain
  namespace: pinniped-supervisor
spec:
  issuer: https://supervisor.lab.rz.jabi-it.de/produktion
  tls:
    secretName: supervisor-tls-cert
  identityProviders: []

Im Issuer ist ein beliebiger Pfad erlaubt, ein Hostname kann so mehrere Issuer tragen. Notieren Sie den Wert wörtlich, er taucht in Schritt 6 unverändert wieder auf.

Prüfung: Der OIDC-Discovery-Endpunkt muss ohne -k antworten, das Zertifikat also von einer bekannten CA stammen.

curl https://supervisor.lab.rz.jabi-it.de/produktion/.well-known/openid-configuration

Schritt 5: Den Identity-Provider anbinden

Zuerst die Client-Zugangsdaten als Secret vom Typ secrets.pinniped.dev/oidc-client:

kubectl create secret generic idp-client-credentials -n pinniped-supervisor \
  --type secrets.pinniped.dev/oidc-client \
  --from-literal=clientID=0oa2fbhcnq1eGZUiG5d7 \
  --from-literal=clientSecret="$IDP_CLIENT_SECRET"

Dann der Provider:

apiVersion: idp.supervisor.pinniped.dev/v1alpha1
kind: OIDCIdentityProvider
metadata:
  name: zentraler-idp
  namespace: pinniped-supervisor
spec:
  issuer: https://idp.lab.rz.jabi-it.de
  authorizationConfig:
    additionalScopes: [groups, email, offline_access]
  claims:
    username: email
    groups: groups
  client:
    secretName: idp-client-credentials

Ohne den Scope groups bekommen Sie keine Gruppenzuordnung, und ohne Gruppen wird die RBAC-Vergabe zur Einzelfallarbeit. Beim Provider tragen Sie als Redirect-URI den spec.issuer der FederationDomain mit angehängtem /callback ein.

Prüfung: kubectl describe OIDCIdentityProvider -n pinniped-supervisor zentraler-idp muss phase: Ready zeigen. Sonst ist der Provider nicht erreichbar oder die Zugangsdaten stimmen nicht. Bei Keycloak ist die Client-Anlage dieselbe Arbeit wie im Beitrag ArgoCD an Keycloak hängen.

Schritt 6: Concierge und Supervisor verbinden

Der JWTAuthenticator im Workload-Cluster ist das Bindeglied. Die Doku zur JWT-Konfiguration verlangt wörtlich, dass sein issuer exakt dem issuer der FederationDomain entspricht.

apiVersion: authentication.concierge.pinniped.dev/v1alpha1
kind: JWTAuthenticator
metadata:
  name: rz-supervisor-authenticator
spec:
  issuer: https://supervisor.lab.rz.jabi-it.de/produktion
  audience: workload1-ed9de33c370981f61e9c
  tls:
    certificateAuthorityData: LS0tLS1CRUdJTiBDRVJUSUZJQ0...0tLQo=

Die audience ist frei wählbar, muss aus Sicherheitsgründen aber je Cluster eindeutig sein. Das base64-kodierte certificateAuthorityData brauchen Sie nur, wenn die CA hinter dem FederationDomain-Zertifikat den Concierge-Pods unbekannt ist.

Prüfung: Beide Issuer maschinell vergleichen, nicht mit dem Auge. Die Ausgaben müssen zeichengleich sein, bis hin zu einem Schrägstrich am Ende.

kubectl get federationdomain -n pinniped-supervisor \
  -o jsonpath='{.items[*].spec.issuer}' --kubeconfig management-admin.yaml
kubectl get jwtauthenticator \
  -o jsonpath='{.items[*].spec.issuer}' --kubeconfig workload-admin.yaml

Schritt 7: kubeconfig erzeugen und anmelden

Die Nutzer-kubeconfig entsteht aus einer Admin-kubeconfig des Workload-Clusters:

pinniped get kubeconfig --kubeconfig "$HOME/admin-kubeconfig.yaml" > pinniped-kubeconfig.yaml

Diese Datei enthält kein Geheimnis mehr, sie beschreibt nur, wie sich die CLI eine Credential holt. Damit dürfen Sie sie verteilen. Den Login löst ein normaler Aufruf aus:

kubectl get namespaces --kubeconfig "$HOME/pinniped-kubeconfig.yaml"

Der erste Aufruf schlägt erwartbar fehl, denn der Nutzer ist authentifiziert, hat aber keine Rechte. Die Autorisierung vergeben Sie über normales RBAC:

kubectl create clusterrolebinding my-user-can-edit \
  --clusterrole edit --user entwickler@lab.rz.jabi-it.de

kubectl create clusterrolebinding my-auditors \
  --clusterrole view --group auditors

Prüfung: pinniped whoami --kubeconfig pinniped-kubeconfig.yaml zeigt Benutzername und Gruppen so, wie der Cluster sie sieht. Stimmen die Gruppen nicht, liegt der Fehler bei den claims aus Schritt 5 und nicht bei RBAC.

Die Lebensdauern, die Sie kennen müssen

Die Referenz zu Tokens und Credentials nennt konkrete Werte.

ArtefaktGültigkeit
Client-Zertifikat5 Minuten, plus 5 Minuten rückdatiert gegen Clock Skew
ID-Token2 Minuten
Access-Token2 Minuten
Refresh-Token9 Stunden ab der ersten Anmeldung
Maximale Sitzungsdauer9 Stunden ab der ersten Anmeldung

Der Nutzer meldet sich also morgens einmal an und arbeitet durch, und was auf dem Laptop liegt, ist nie länger als fünf Minuten gültig. Keiner dieser Werte ist konfigurierbar.

Die folgenreichsten Stolpersteine

1. Nicht-privilegierte Nutzer lesen die Pinniped-Secrets

Symptom: Ein Nutzer ohne Administratorrechte kann Secrets im Namespace pinniped-supervisor lesen.

Ursache: Die Manifeste bringen keine Absicherung gegen Lesezugriffe auf den eigenen Namespace mit. Die Doku fordert diesen Schutz als eigenen Schritt ein.

Prüfung: Die Antwort muss no lauten.

kubectl auth can-i get secrets -n pinniped-supervisor --as entwickler@lab.rz.jabi-it.de

Lösung: RBAC so setzen, dass Nicht-Administratoren die Secrets in pinniped-concierge und pinniped-supervisor nicht lesen können.

2. Der Login scheitert, obwohl alles Ready meldet

Symptom: Supervisor und Concierge laufen, alle Ressourcen melden Ready, der Login schlägt trotzdem fehl.

Ursache: Der issuer im JWTAuthenticator weicht vom issuer der FederationDomain ab, etwa durch einen abweichenden Pfad oder einen Schrägstrich am Ende.

Prüfung: Die beiden jsonpath-Abfragen aus Schritt 6 gegeneinander stellen.

Lösung: Den Wert wörtlich aus der FederationDomain übernehmen. Die Doku verlangt eine exakte Übereinstimmung, keine sinngemäße.

3. --anonymous-auth=false sperrt alle Nutzer aus

Symptom: Nach dem Setzen von --anonymous-auth=false am API-Server kann sich niemand mehr anmelden.

Ursache: Die TokenCredentialRequest-API des Concierge ist auf anonymen Zugriff angewiesen. Wird der abgeschaltet, bricht der Login-Pfad.

Prüfung: Nach der Änderung pinniped whoami mit der Pinniped-kubeconfig ausführen.

Lösung: --anonymous-auth=false nur auf Clustern setzen, die die Impersonation-Proxy-Strategie verwenden.

Die vollständige Sammlung der Stolpersteine

Diese drei Fälle sind die folgenreichsten, sie sind aber nicht alle. Die vollständige Sammlung aller sechzehn Stolpersteine steht im Beitrag Pinniped: die Stolpersteine bei Supervisor, Concierge und CLI, jeder nach Symptom, Ursache, Prüfung und Lösung geordnet. Dort stehen unter anderem der ungefragt auftauchende LoadBalancer, die geteilte audience, der Registry-Wechsel ab v0.40.0 und der Login für CI/CD-Konten.

Grenzen

Der Entzug wirkt nicht sofort. Identitäts- und Gruppeninformationen werden erst beim Refresh revalidiert. Die Doku beziffert die Veraltung nach einem Refresh auf 2 + 2 + 5 = 9 Minuten. Nach der ersten Anmeldung kommen die 10 Minuten des Authorization Code hinzu, im schlimmsten Fall also 10 + 2 + 2 + 5 = 19 Minuten. Typisch sind laut Doku etwa 5 Minuten. Ein im Identity-Provider deaktivierter Nutzer kommt also noch kurze Zeit an den Cluster. Wer sofortigen Entzug braucht, muss zusätzlich im Cluster eingreifen, etwa über RBAC.

Die Maximalsitzung liegt fest bei 9 Stunden. Verlangen Ihre Vorgaben einen kürzeren Wert, ist das mit Bordmitteln nicht erreichbar.

Service-zu-Service-Authentifizierung ist nicht abgedeckt. Dafür brauchen Sie einen anderen Mechanismus.

Der Supervisor wird zur zentralen Abhängigkeit. Ist er nicht erreichbar, kommt niemand mehr an die angeschlossenen Cluster. Halten Sie einen Notfallzugang außerhalb des Pinniped-Pfads bereit.

Ich halte den Aufwand für gerechtfertigt, sobald es mehr als eine Handvoll Cluster gibt. Der Gewinn ist nicht nur die kurze Lebensdauer, sondern dass der Cluster-Zugang aufhört, ein Sonderfall zu sein. Wer keinen Identity-Provider aufbauen will, fährt mit einem eng geführten Zugangsweg besser, wie im Beitrag Wenn der einzige Zugang die Rancher-Shell ist beschrieben.

Sie wollen den Zugang zu Ihren Systemen an echte Identitäten binden, statt an Schlüssel, die nie ablaufen? Ich baue Zugangswege, die zentral steuerbar sind und mit der Sitzung enden. Mehr unter IT-Sicherheit & ISMS, das Erstgespräch ist unverbindlich.

Alex Jabi, Jabi IT

Alex Jabi

Ich betreue IT, Informationssicherheit und Datenschutz für KMU und Praxen an der Bergstraße und im Odenwald, persönlich, dokumentiert und ohne Cloud-Zwang.

Mehr über mich
Zurück zum Blog

Passende Artikel

Alle Artikel »
Wenn der einzige Zugang die Rancher-Shell ist

Wenn der einzige Zugang die Rancher-Shell ist

Kein kubeconfig, kein kubectl von außen, nur die Kubectl-Shell im Browser. Wie man darin sauber arbeitet: Rechte feststellen, Manifeste ohne Datei-Upload anlegen, vor dem Schreiben prüfen und Ergebnisse einsammeln, ohne interaktiv im Cluster herumzustochern.

ArgoCD an Keycloak hängen: SSO für das GitOps-Werkzeug

ArgoCD an Keycloak hängen: SSO für das GitOps-Werkzeug

Vom leeren Keycloak-Realm bis zur Gruppe, die in ArgoCD eine Rolle bekommt. Beide Seiten Schritt für Schritt, mit dem Mapper, an dem es hängt, und vier Stolpersteinen, darunter einer, bei dem eine Verbotsregel wirkungslos bleibt.

Die eigene Registry mit Harbor: scannen, cachen, absichern

Die eigene Registry mit Harbor: scannen, cachen, absichern

Harbor speichert Container-Images nicht nur, es scannt sie mit Trivy und spiegelt fremde Registries als Proxy-Cache. Der Scanner ist dabei nicht im Standard-Setup enthalten, und die Sperre für verwundbare Images greift beim Pull statt beim Push. Aufbau mit Prüfbefehlen und die dokumentierten Fallen.