Skip to content

Add kubectl plugin - #681

Open
lbajsarowicz wants to merge 6 commits into
1Password:mainfrom
lbajsarowicz:feat/kubectl-plugin
Open

lbajsarowicz wants to merge 6 commits into
1Password:mainfrom
lbajsarowicz:feat/kubectl-plugin

Conversation

@lbajsarowicz

@lbajsarowicz lbajsarowicz commented Oct 8, 2026 •

Copy link
Copy Markdown

Overview

Adds a kubectl shell plugin, as requested in the community thread "Any plans for creating a kubectl (.kube/config) CLI plugin?".

A kubeconfig can hold two kinds of static secrets: a bearer token, or a client certificate with its private key (client-certificate-data / client-key-data). The plugin moves those into a 1Password item (Address, Token, Certificate, Private Key, Certificate Authority) and provides them to kubectl only for the context whose cluster matches the item's Address.

How provisioning works: the plugin resolves the config sources the way kubectl does (--kubeconfig, then KUBECONFIG, then ~/.kube/config), merges them with kubectl's first-wins rules, and resolves the target context and server (--context, --cluster, --server, then current-context). When the server matches the item's Address, it writes a temporary kubeconfig overlay that redefines only that one context, pointing it at a per-invocation user that carries the item's secrets, and puts the overlay first in KUBECONFIG. Clusters, other contexts and current-context stay the user's own. When the server does not match, nothing is provisioned and kubectl behaves exactly as without the plugin, so kubectl config use-context and --context keep working (this is the class of problem reported for Argo CD in #526). With --kubeconfig F, the flag is moved into KUBECONFIG=<overlay>:F, the same approach the ngrok and aws plugins use to rewrite the command line. No secret ever appears in the command line.

The importer reads the active kubeconfig set (KUBECONFIG or ~/.kube/config) and offers one item per context with a static secret. Users authenticated through exec plugins or auth-provider (EKS, GKE, AKS, OIDC) have nothing to import and are left untouched; tokenFile users are skipped as their token is usually rotated.

Local-only commands (config, completion, options, plugin, kustomize, kuberc, help, version --client, shell completion) do not require authentication. config in particular must never run with the overlay, because config set-* writes into the first KUBECONFIG file.

Things worth a maintainer's opinion:

  • PEM values are stored single-line base64, as they appear in kubeconfig *-data fields; the provisioner also accepts raw PEM. If multi-line fields are well supported in items, PEM could become the canonical form.
  • Certificate and Private Key are reused for the client pair and one new field name, Certificate Authority, is added. Client Certificate / Client Key would be the alternative.
  • On a machine with no kubeconfig at all (and no KUBECONFIG, KUBERNETES_SERVICE_HOST, KUBERNETES_MASTER), the item alone produces a standalone config for its cluster.
  • Known limits, documented rather than solved: a kuberc file that declares aliases or connection-related defaults (server, context, cluster, user, auth, TLS, proxy) makes the plugin step aside, fail-closed, and KUBECTL_KUBERC=false is not honoured, so kuberc is always treated as active; external kubectl-* plugins are treated as needing the cluster; URL equality is the cluster identity, as in the Argo CD plugin.

Type of change

  • Created a new plugin
  • Improved an existing plugin
  • Fixed a bug in an existing plugin
  • Improved contributor utilities or experience

Related Issue(s)

How To Test

Unit tests cover the parser, the kubeconfig loader and merge rules, server normalisation, the provisioner (context match and mismatch, --kubeconfig, multi-file KUBECONFIG, fresh machine, impersonation fields, kuberc), the importer and the needs-auth rule:

go test ./plugins/kubectl/ -v
make kubectl/validate

With the CLI, using an item whose Address is your cluster's server and a kubeconfig that also has a second, local context:

make kubectl/build
op plugin init kubectl
kubectl get nodes                       # authenticated with the 1Password item
kubectl --context <local-context> get nodes   # untouched: uses the local context's own credentials
kubectl config view --minify            # shows the local context, no overlay, no prompt

op plugin init kubectl imports every context of ~/.kube/config (or the files in KUBECONFIG) that carries a token or a client certificate pair.

Verified end to end with 1Password CLI 2.40.0 and kubectl v1.37.1 against a Scaleway Kapsule cluster (Kubernetes 1.37): the token was imported from a kubeconfig obtained with scw k8s kubeconfig get … auth-method=legacy, kubectl get pods, logs and exec -it … -- sh authenticate through the item, and the same commands against a local docker-desktop context are left untouched.

Changelog

Authenticate kubectl with a token or client certificate stored in 1Password, provided only to the context that targets the item's cluster.

Tokenises the arguments kubectl receives: values of value-taking global flags are consumed, boolean flags follow pflag semantics with last-wins, underscores are normalised to dashes, shorthand clusters are split, and "--" ends option parsing only at an option boundary. Shapes the parser cannot resolve, such as a subcommand-local flag followed by a server override, are reported as ambiguous so the provisioner can decline.
Typed kubeconfig structs that round-trip through yaml.v2, a per-file reader with duplicate-name detection, a merger that follows kubectl's first-wins rules, strict normalisation of API server URLs for matching, and a converter that accepts PEM or base64-encoded PEM and checks the block type. Adds the Certificate Authority field name to the SDK.
Local-only commands (config, completion, options, plugin, kustomize, kuberc, help, shell completion hooks, version --client) and commands that pass their own credentials on the command line skip 1Password. Everything else, including external kubectl plugins, may contact the API server and needs the item.
…matching context

Resolves the config sources and the target context the way kubectl does, and only when the target server matches the item's Address writes a temporary overlay that redefines that one context to use a per-invocation user carrying the item's token or client certificate. The overlay goes first in KUBECONFIG; the user's clusters, other contexts and current-context stay untouched. Impersonation fields are preserved. A kuberc file with aliases or connection-related defaults, an ambiguous command line, or explicit auth flags make the plugin step aside. On a machine with no kubeconfig at all the item alone produces a standalone config.
Reads the KUBECONFIG files, or ~/.kube/config, merges them as kubectl would and offers one item per context whose user holds a bearer token or a client certificate pair. Users authenticated through exec plugins, auth providers or a token file are left alone. Referenced certificate files are resolved relative to the file that names them and stored as base64; diagnostics name paths only.
@lbajsarowicz
lbajsarowicz marked this pull request as ready for review October 8, 2026 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant