ProxyAuthK8S

Plugin kubectl

Utiliser ProxyAuthK8S depuis kubectl

Le plugin kubectl proxyauth est le pendant client de ProxyAuthK8S : il gère la connexion OIDC, stocke les identifiants dans le trousseau du système, et sert de credential plugin kubectl pour que kubectl parle à n'importe quel cluster exposé.

Installation

Via mise

mise use -g github:batleforc/ProxyAuthK8S

mise télécharge l'archive de la release GitHub correspondant à l'OS et à l'architecture, et met kubectl-proxyauth dans le PATH. Pour figer une version : mise use -g github:batleforc/ProxyAuthK8S@v0.2.1.

Le plugin n'est pas publié sur l'index krew pour le moment. Le manifeste krew reste rendu à chaque tag et attaché à la release GitHub.

Depuis une release

VERSION=v0.2.1
curl -sSL -o kubectl-proxyauth.tar.gz \
  "https://github.com/batleforc/proxyauthK8s/releases/download/${VERSION}/kubectl-proxyauth_${VERSION}_linux_amd64.tar.gz"
tar xzf kubectl-proxyauth.tar.gz
install -m 0755 kubectl-proxyauth ~/.local/bin/

Le binaire doit s'appeler kubectl-proxyauth et être dans le PATH : c'est ce qui permet à kubectl de l'exposer comme kubectl proxyauth.

Sur Linux, les identifiants sont stockés dans le trousseau via l'API Secret Service (gnome-keyring, KWallet...). Si aucun Secret Service n'est joignable (machine sans interface graphique, session SSH sans bus D-Bus), le plugin se replie sur le trousseau du noyau (keyutils) : les tokens y sont protégés mais ne survivent pas à un redémarrage, il faudra alors se reconnecter.

Les tokens sont rangés sous le service proxyauthk8s, par URL de serveur. Pour garder deux profils sur le même serveur (deux comptes, deux HOME), donnez à chacun son service avec PROXYAUTH_KEYRING_SERVICE=<nom> : sans cela, le dernier login remplace le token de l'autre.

Usage

Se connecter au serveur

kubectl proxyauth login --server-url https://proxyauthk8s.example.com

Sans --token, le login serveur est une connexion SSO : le plugin ouvre le navigateur sur /api/v1/auth/login du serveur (avec --browser, PROXYAUTH_BROWSER et le collage d'URL comme pour un cluster, voir plus bas). Après la connexion chez l'IdP du proxy, le navigateur revient sur le listener local (http://localhost:18000/, PROXYAUTH_CALLBACK_PORT) avec un code à usage unique, que le plugin échange (PKCE) contre la session : jeton d'accès et refresh token, rangés dans le trousseau. Aucun jeton ne passe dans une URL.

Le jeton d'accès est renouvelé tout seul (/api/v1/auth/refresh) quand il lui reste moins de 60 s, à l'usage (get-token, get, login <cluster>). Si la session SSO est terminée, le plugin demande de relancer kubectl proxyauth login --server-url … ; si l'IdP est injoignable, il le dit et il suffit de réessayer plus tard.

kubectl proxyauth login --server-url https://proxyauthk8s.example.com --token <jeton>

Avec --token (scripts, CI), le jeton collé est validé auprès du serveur puis stocké tel quel, sans renouvellement : il faut se reconnecter à son expiration.

Certificat non reconnu par le système

Si le certificat TLS de ProxyAuthK8S est auto-signé ou émis par une CA interne, le login échoue avec certificate verify failed. Donnez au plugin le certificat de la CA (PEM) :

kubectl proxyauth login --server-url https://proxyauthk8s.example.com \
  --certificate-authority ./proxyauth-ca.pem

La CA est enregistrée pour ce serveur dans ~/.kube/proxyauth_config.yaml : les commandes suivantes (et les logins de cluster) lui font confiance sans repréciser l'option. Elle est aussi écrite en certificate-authority-data dans les clusters du kubeconfig, pour que kubectl lui fasse confiance. Repasser --certificate-authority la remplace.

Confiance au premier usage. Lors du premier login à un serveur https sans CA connue, le plugin récupère le certificat présenté (la poignée de main est interrompue dès sa réception : rien n'est envoyé à un serveur non vérifié). Si le système ne le reconnaît pas mais qu'il s'agit d'un certificat auto-signé valide pour ce nom d'hôte (certificat du serveur lui-même, ou racine envoyée avec la chaîne), le plugin affiche son sujet, sa validité et son empreinte SHA-256, puis demande confirmation :

The server https://proxyauthk8s.example.com presents a self-signed certificate this system does not trust:
  Subject:  CN=proxyauthk8s.example.com
  Valid:    2026-10-01T00:00:00Z to 2027-10-01T00:00:00Z
  SHA-256:  3F:A1:…:9C
Check this fingerprint with the server's administrator before accepting.
Trust this certificate for https://proxyauthk8s.example.com? [y/N]:

Vérifiez l'empreinte auprès de l'administrateur (par ex. openssl x509 -noout -fingerprint -sha256 -in cert.pem) avant d'accepter. Une réponse y l'enregistre exactement comme --certificate-authority ; toute autre réponse arrête le login (ERR000020). Rien n'est proposé sans terminal (scripts, CI), ni quand le certificat est expiré, émis pour un autre nom, ou signé par une CA que le serveur n'envoie pas : passez alors la CA avec --certificate-authority.

Renouvellement du certificat. Un certificat auto-signé épinglé ne vérifie plus le serveur dès qu'il est renouvelé avec une nouvelle clé — ce que fait cert-manager par défaut (rotationPolicy: Always, environ tous les 60 jours). Les commandes échouent alors (ERR000020 pour le plugin, x509: certificate signed by unknown authority pour kubectl). Relancez kubectl proxyauth login depuis un terminal : le plugin détecte le changement et affiche l'ancienne et la nouvelle empreinte :

WARNING: the certificate of https://proxyauthk8s.example.com has CHANGED since it was trusted.
Previously trusted SHA-256: 3F:A1:…:9C
Now presented:
  Subject:  CN=proxyauthk8s.example.com
  Valid:    2026-12-01T00:00:00Z to 2027-12-01T00:00:00Z
  SHA-256:  B7:02:…:E4
This is expected after a certificate renewal, but it is also what an attacker
intercepting the connection would show. Check the new fingerprint with the
server's administrator before accepting.
Replace the trusted certificate for https://proxyauthk8s.example.com? [y/N]:

Le défaut est non : un changement inattendu est exactement ce que montrerait une interception. En acceptant, le nouveau certificat remplace l'ancien pour ce serveur et dans tous les clusters du kubeconfig qui passent par lui, sans relogin cluster par cluster (même chose quand --certificate-authority change la CA d'un serveur). Sans terminal, rien n'est remplacé.

Pour un serveur utilisé dans la durée, évitez d'épingler un certificat feuille qui tourne : servez un certificat émis par une CA (interne ou publique) et distribuez cette CA avec --certificate-authority, ou envoyez une racine auto-signée stable avec la chaîne — seule la rotation de cette racine demande alors une nouvelle confirmation.

Pour récupérer la CA :

  • cert-manager avec une CA interne : kubectl get secret <secret-du-certificat> -n <ns> -o jsonpath='{.data.ca\.crt}' | base64 -d

  • mkcert (dev local) : $(mkcert -CAROOT)/rootCA.pem

  • certificat auto-signé : le certificat lui-même, tel que servi par le serveur :

    openssl s_client -connect proxyauthk8s.example.com:443 -servername proxyauthk8s.example.com </dev/null \
      | openssl x509 > proxyauth-ca.pem

Récupérer le certificat depuis le serveur lui-même revient à lui faire confiance sur parole (trust on first use) : vérifiez son empreinte (openssl x509 -in proxyauth-ca.pem -noout -fingerprint -sha256) auprès de l'administrateur. Pour une CA interne, le serveur n'envoie en général pas la racine : prenez-la à la source.

Voir où l'on est connecté

kubectl proxyauth status          # tous les serveurs connus
kubectl proxyauth status -f json  # même chose en json/yaml
 DEFAULT  SERVER                              LOGIN  USER   EXPIRES  CLUSTERS
 *        https://proxyauthk8s.example.com    sso    alice  in 42m   default/mon-cluster

status lit uniquement l'état local (configuration et trousseau) : aucun appel réseau, et aucun jeton n'est affiché. LOGIN vaut sso (session renouvelée à l'usage), token (jeton collé, pas renouvelé) ou none. USER et EXPIRES sont lus dans le jeton quand c'est un JWT, sans en vérifier la signature : c'est un affichage, pas un contrôle d'accès.

Lister les clusters visibles

kubectl proxyauth get              # tous les clusters visibles
kubectl proxyauth get mon-cluster  # un seul cluster
kubectl proxyauth get -f json      # sortie json/yaml au lieu du tableau

Seuls les clusters dont expose_via_dashboard est activé et dont le groupe dashboard figure dans les groupes de l'utilisateur apparaissent ici.

Se connecter à un cluster

Pour un cluster dont le provider est OIDC/SSO, la connexion est interactive :

kubectl proxyauth -n default login mon-cluster

Le plugin ouvre le navigateur sur le provider OIDC, récupère code/state via un callback local (http://localhost:18000/ par défaut), échange le code auprès du serveur et stocke l'id_token du cluster dans le trousseau.

L'URI de redirection utilisée est http://localhost:<port>/auth/callback/<ns>/<cluster> et doit être enregistrée pour le client OIDC du cluster côté IdP. Le port par défaut est 18000 ; changez-le avec PROXYAUTH_CALLBACK_PORT si besoin (et enregistrez l'URI correspondante).

Après la connexion, le provider redirige le navigateur vers http://localhost:<port>/auth/callback/<ns>/<cluster>?code=…&state=…. Ce localhost est celui de la machine du navigateur : quand le plugin tourne ailleurs (workspace Eclipse Che, session SSH, conteneur distant), la redirection ne l'atteint pas et la page ne se charge pas. C'est attendu : depuis un terminal, le plugin accepte aussi qu'on colle l'URL de cette page.

kubectl proxyauth login mon-cluster --browser none   # n'essaie pas d'ouvrir un navigateur local
  1. Ouvrez l'URL affichée dans le navigateur de votre poste et connectez-vous.
  2. Le navigateur arrive sur http://localhost:18000/auth/callback/... et affiche une erreur de connexion : copiez l'adresse complète depuis la barre d'adresse.
  3. Collez-la dans le terminal et validez. Le plugin termine le login (échange du code, kubeconfig).
  • Le collage et le callback local sont attendus en même temps : sur un poste classique, rien ne change, le premier arrivé l'emporte.
  • L'adresse complète, ?code=…&state=… ou code=…&state=… sont acceptés ; une saisie qui n'est pas une redirection est signalée et l'attente continue. Une erreur renvoyée par le provider (error=access_denied, …) arrête le login avec son détail.
  • Le délai d'attente passe de 3 à 10 minutes quand le collage est possible. Sans terminal (script), seul le callback local est attendu.
  • state reste vérifié par le serveur : coller l'URL d'un autre login échoue.

Choisir le navigateur

Par défaut, le navigateur du système est utilisé. Si le provider impose un autre navigateur (navigateur d'entreprise, profil dédié), indiquez-le avec --browser, et ses arguments avec --browser-arg (répétable) :

# Linux / macOS
kubectl proxyauth login mon-cluster --browser /opt/corp/browser
kubectl proxyauth login mon-cluster --browser google-chrome \
  --browser-arg=--profile-directory=Work --browser-arg=--new-window

# Windows : chemin complet, sans guillemets supplémentaires à prévoir
kubectl proxyauth login mon-cluster --browser "C:\Program Files\Corp\browser.exe"
  • Le programme est lancé directement, sans shell : l'URL est toujours un seul argument, et un chemin avec des espaces n'a pas besoin d'échappement.
  • L'URL est passée en dernier argument, sauf si un argument contient {url}, qui est alors remplacé (ex. --browser-arg=--app={url}).
  • Le choix est enregistré pour le serveur (visible dans la colonne Browser de kubectl proxyauth config get) : les logins suivants via ce serveur l'utilisent sans repréciser l'option. Il peut aussi être donné dès le login serveur.
  • --browser none n'ouvre rien et se contente d'afficher l'URL (poste sans navigateur, URL à ouvrir ailleurs) ; --browser default revient au navigateur du système.
  • PROXYAUTH_BROWSER=<programme> remplace le choix enregistré pour une seule exécution, sans le modifier.

Pour un cluster non-SSO (ou pour fournir un jeton directement) :

kubectl proxyauth -n default login mon-cluster --token <jeton>

Dans les deux cas, le jeton est stocké dans le trousseau, puis login écrit dans le kubeconfig (--kubeconfig, sinon $KUBECONFIG, sinon ~/.kube/config) un cluster <ns>-<cluster>, un utilisateur <ns>-<cluster>-proxyauth et un contexte <ns>-<cluster>-context, qui devient le contexte courant. Les autres entrées ne sont pas modifiées, et un nouveau login met ces trois entrées à jour au lieu de les dupliquer.

Comme kubectl, le plugin accepte un $KUBECONFIG listant plusieurs fichiers (séparés par :, ; sous Windows) : il lit leur fusion et écrit uniquement dans le premier fichier existant (créé s'il n'en existe aucun). Ce fichier étant prioritaire lors de la fusion, ce qui y est écrit l'emporte sur une entrée de même nom dans un fichier suivant, sans modifier ce dernier.

L'exec de l'utilisateur appelle kubectl proxyauth get-token, qui relit le jeton dans le trousseau à chaque commande kubectl :

kubectl proxyauth -n default login mon-cluster
kubectl get pods   # passe par le proxy avec le jeton du trousseau

Quand le jeton est un JWT (l'id_token d'un login OIDC, ou le jeton d'une session SSO), get-token indique à kubectl son expiration (expirationTimestamp). kubectl relance alors get-token à l'échéance, y compris pendant une commande longue (port-forward, exec, --watch), ce qui renouvelle le jeton quand une session SSO le permet. Un jeton déjà expiré n'est pas transmis : get-token échoue et indique le login à relancer, au lieu de laisser kubectl recevoir un 401.

Cluster en échange de jeton

Un cluster en upstream_auth.mode: TokenExchange (token_exchange: true dans /api/v1/clusters) prend le jeton du serveur : login mon-cluster ne lance aucun SSO et ne stocke aucun jeton de cluster (un --token est ignoré). Il écrit le même contexte et note le cluster comme token_exchange dans la configuration du plugin ; get-token rend alors le jeton du serveur, renouvelé s'il expire dans moins de 60 s.

Gérer les contextes kubectl

kubectl proxyauth context                                # contexte courant (alias : ctx)
kubectl proxyauth get-contexts                           # tous les contextes du kubeconfig
kubectl proxyauth use-context default-mon-cluster-context   # change le contexte courant

Les anciennes formes context --list et context --set <nom> marchent encore, avec un avertissement : elles disparaîtront dans une prochaine version.

Se déconnecter / purger le cache

kubectl proxyauth logout mon-cluster   # retire le jeton d'un cluster
kubectl proxyauth logout               # déconnecte du serveur (tous ses jetons)
kubectl proxyauth cache clear          # purge tous les jetons en cache

Configuration du plugin

Le plugin garde sa configuration (serveurs connus, namespace par défaut) dans ~/.kube/proxyauth_config.yaml (surchargeable avec -p/--proxy-auth-config).

kubectl proxyauth config get                     # configuration courante
kubectl proxyauth config get --list              # toutes les configurations
kubectl proxyauth config use-server <url>            # serveur par défaut
kubectl proxyauth config set-namespace <url> <ns>    # namespace par défaut d'un serveur
kubectl proxyauth config clear --server-url <url>    # oublie un serveur
kubectl proxyauth config clear --all

Le premier serveur auquel on se connecte devient le serveur par défaut. config set-def (remplacée par use-server et set-namespace) marche encore, avec un avertissement.

Options globales

Une erreur s'affiche sur une ligne error: ERR0000xx: …, suivie au besoin d'une ligne hint: qui donne la commande à lancer. Le code reste stable d'une version à l'autre.

OptionEffet
-s, --server-url <URL>Serveur ProxyAuthK8S à utiliser (sinon le serveur par défaut)
-n, --namespace <NS>Namespace du cluster visé
-k, --kubeconfig <FILE>Kubeconfig (défaut : $KUBECONFIG puis ~/.kube/config)
-p, --proxy-auth-config <FILE>Configuration du plugin (défaut : ~/.kube/proxyauth_config.yaml)
-f, --format <FORMAT>table (défaut), json ou yaml
-v / -vvLogs de debug, de trace (horodatés)

Le kubeconfig plugin

C'est ce que login écrit, et la forme téléchargeable depuis le dashboard (kubeconfig plugin) :

apiVersion: v1
kind: Config
clusters:
  - name: default-mon-cluster
    cluster:
      server: https://proxyauthk8s.example.com/clusters/default/mon-cluster
users:
  - name: default-mon-cluster-proxyauth
    user:
      exec:
        apiVersion: client.authentication.k8s.io/v1
        command: kubectl
        args:
          - proxyauth
          - get-token
          - --namespace=default
          - --server-url=https://proxyauthk8s.example.com
          - mon-cluster
        interactiveMode: Never
contexts:
  - name: default-mon-cluster-context
    context:
      cluster: default-mon-cluster
      user: default-mon-cluster-proxyauth
current-context: default-mon-cluster-context

L'URL du serveur est celle du proxy, pas celle du cluster : c'est ProxyAuthK8S qui authentifie l'appel, applique les règles de sécurité, puis relaie vers l'apiserver.

Résolution de problèmes

SymptômeCause probable
401 sur toutes les requêtesJeton expiré : relancer kubectl proxyauth login
the session with … is overSession SSO du serveur terminée : relancer kubectl proxyauth login --server-url …
the identity provider is unavailableIdP du proxy injoignable au renouvellement : réessayer plus tard
403 avec un message sur un groupeL'utilisateur n'est pas dans le proxy_group du cluster
403 avec un message sur un cheminLe chemin n'est pas dans security_config.allowed_resources
429 avec un en-tête Retry-AfterRate limiting, ou bannissement après des échecs d'authentification répétés
certificate verify failedCertificat du serveur non reconnu : voir --certificate-authority ci-dessus
ERR000014: Unauthenticated: the login to cluster … has expiredL'id_token du cluster (ou le jeton serveur collé) a expiré : lancer la commande indiquée, par ex. kubectl proxyauth -n <ns> login <cluster>
ERR000021: Not logged in to any ProxyAuthK8S serverAucun serveur connu : commencer par kubectl proxyauth login --server-url https://…
ERR000020: Server certificate not trustedCertificat auto-signé refusé à l'invite de confiance, ou certificat renouvelé depuis qu'il a été épinglé : relancer kubectl proxyauth login depuis un terminal et accepter après vérification de l'empreinte, ou passer --certificate-authority
x509: certificate signed by unknown authority (kubectl)Le certificat du serveur a changé : relancer kubectl proxyauth login, qui met à jour la CA des clusters du kubeconfig
Le cluster n'apparaît pas dans getexpose_via_dashboard est à false (défaut) ou le groupe dashboard ne correspond pas
502 the cluster does not trust this proxyCluster en FrontProxy dont l'apiserver ne croit plus le proxy : se reconnecter n'y fait rien, prévenir l'opérateur (diagnostic)
kubectl auth whoami affiche proxyauth:…Normal en FrontProxy : l'apiserver voit le nom préfixé, c'est lui que les RoleBinding visent

On this page