kubectl add is a kubectl plugin that installs things into your cluster from
whatever you point it at — a YAML URL, a kustomization, a helm chart, a helm
chart repository, or a git repo — and applies them server-side, so it
feels like native kubectl.
You give it a resource; the plugin sniffs out what it is, resolves the installable artifact, and applies it inside the cluster as you — forwarding your own credential into a short-lived Secret, so the apply is constrained by your RBAC and no kubeconfig is copied in.
- 🧠 Smart resolution — point it at a YAML URL, a kustomization, a helm chart, a chart repo, or a git repo (GitHub, GitLab, Bitbucket); it sniffs out what it is.
- ☁️ Server-side apply — runs
kubectlinside the cluster; your local kubeconfig is never copied in. - 🔑 Runs as you — forwards your own credential into a short-lived Secret; the apply uses your identity and RBAC, no ServiceAccount, no escalation.
- 🎛️ Kustomize, built in-cluster — relative resources,
bases, nested kustomizations, and remote git/http references all resolve. - ⎈ Helm, no tiller, no fuss — renders charts client-side; installs from loose files, an HTTP chart repository, or a git repo.
- 📌 Pin what you want —
?chart=and?version=select straight from a repository index. - 🗑️ Reversible —
--removedeletes exactly what you added. - 🌐 Public tunnel —
kubectl add tunnelexposes the API server (or a service) over a Cloudflare quick tunnel, raw-forwarded so callers still authenticate. - 🪶 Feels native — one command, standard kubectl flags (
--namespace,-v, kubeconfig).
Homebrew (macOS and Linux):
brew tap scaffoldly/tap
brew install kubectl-addOr grab a binary from
GitHub Releases — each
archive holds the kubectl-add binary plus the LICENSE, and every release is
cosign-signed and SLSA-attested (verification in SECURITY.md).
Put kubectl-add on your PATH and kubectl discovers it as kubectl add.
Or build from source:
git clone https://github.com/scaffoldly/kubectl-add
cd kubectl-add
make install # builds to $HOME/.local/bin/kubectl-addConfirm kubectl sees it:
kubectl add --helpA binary installed from the GitHub release, make install, the curl script, or
the Homebrew tap keeps itself up to date: on a normal run it checks for a
newer release at most once a day and, if there is one, downloads it,
verifies the checksum and cosign signature, and swaps it in — repointing
the symlink for the versioned layout, or replacing the binary in place for a
tap/bare install. Updates fail open: a hiccup never blocks your kubectl add.
kubectl add --update # update now, then exit
export KUBECTL_ADD_NO_AUTO_UPDATE=1 # disable the automatic daily checkInstalls owned by a manager with a read-only or self-managed store — krew
and Nix — are left alone; the updater points you at
kubectl krew upgrade / nix profile upgrade instead. (A future
homebrew-core build will opt out at compile time, since core forbids
self-updating software; the tap build does not.)
Point it at a resource and it resolves the format and applies it server-side.
Scope any of these to a namespace with --namespace, or undo with --remove:
kubectl add <resource> --namespace demo
kubectl add <resource> --removeA URL to one or more manifests, applied as-is:
kubectl add https://k8s.io/examples/application/deployment.yamlA kustomization, built server-side (relative resources, bases, and remote git/http references are all resolved):
kubectl add https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/examples/helloWorld/kustomization.yamlA chart repository (its index.yaml is sniffed automatically), an OCI
registry, a git repo (defaults to the latest release and finds the chart),
or a chart served as loose Chart.yaml files over HTTP:
# a chart repository (picks the chart, latest version)
kubectl add https://kubernetes.github.io/ingress-nginx
# pin the chart and version from a repository
kubectl add "https://kubernetes.github.io/ingress-nginx?chart=ingress-nginx&version=4.15.1"
# an OCI registry (latest tag, or pin with :tag or ?version=)
kubectl add oci://mirror.gcr.io/bitnamicharts/nginx
# a GitHub repo
kubectl add kubernetes/ingress-nginxInstalling a chart opens its values in your editor first (the reconciled
ConfigMap); save to continue, or skip the edit with --no-edit:
kubectl add https://kubernetes.github.io/ingress-nginx # edits, then installs
kubectl add https://kubernetes.github.io/ingress-nginx --no-edit # installs with saved valuesThe edit is skipped automatically when stdin is not a terminal (scripts, CI).
Expose the API server — or a Service reached through it — to the public
internet over a Cloudflare quick tunnel,
driven in-process (no cloudflared binary). The public URL is printed and the
tunnel runs until you interrupt it:
kubectl add tunnel # the API server (default)
kubectl add tunnel kubernetes # the API server (explicit)
kubectl add tunnel svc/my-app -n demo # a Service, via the API server proxyThe tunnel forwards raw and injects no credentials of its own — callers
hitting the public URL authenticate exactly as they would against the API
server directly. The default (API server) target points the tunnel straight at
your current context's cluster URL. A Service target routes through the API
server's services/proxy subresource, so the caller needs the matching RBAC.
Nothing is granted by opening the tunnel.
⚠️ This publishes an API server endpoint to the internet for the tunnel's lifetime. Anyone with the URL can reach it (and still has to authenticate). Use it for short-lived demos and debugging, not as a standing ingress.
The same fluent builder is importable from the module root:
import "github.com/scaffoldly/kubectl-add"
err := kubectladd.New().
WithResource("https://github.com/some/repo").
WithNamespace("my-namespace").
Run()The connection is inferred from your kubeconfig, or supply one explicitly with
WithRESTConfig(cfg). Pass a context.Context for cancellation/deadlines with
WithContext(ctx).
What kubectl add can resolve and install, by source and format:
| Source | YAML | Kustomize | Helm |
|---|---|---|---|
| HTTP(S) URL | ✅ | ✅ | ✅ loose Chart.yaml, repo index.yaml |
GitHub (org/repo, .git, …/tree/…, …/blob/…) |
✅ blob/ |
✅ root or a subdir | ✅ charts/ or a subdir, full file set |
GitLab (…/-/tree/…, …/-/blob/…, subgroups) |
✅ blob/ |
✅ root or a subdir | ✅ charts/ or a subdir, full file set |
Bitbucket (…/src/…) |
✅ | ✅ root or a subdir | ✅ charts/ or a subdir, full file set |
OCI (oci://) |
— | — | ✅ registry, latest tag or pinned |
✅ supported · 🚧 planned · — n/a
Notes:
- A bare
org/reporesolves at the repo's latest release (GitHub default host); a full URL pins the ref and subpath — GitHub/GitLab via…/tree/<ref>/<path>or…/blob/<ref>/<file>(GitLab prefixes these with/-/), Bitbucket via…/src/<ref>/<path>. Each resolves to its host's raw URL, and helm charts fetch their full file set via the git tree (no conventional-path guessing). Bitbucket has no releases, so a bare repo resolves at its latest tag (then the main branch). SetGITHUB_TOKEN/GITLAB_TOKEN/BITBUCKET_TOKENto raise rate limits or reach private repos. - Kustomizations sourced from a URL support relative resources,
bases, nested kustomizations, and remote git/http references. Some kustomize fields that reference local files are not yet materialized (#1). - Helm charts install from loose files, an HTTP chart repository, or an OCI
registry (including repositories whose
index.yamlpoints atoci://).?chart=and?version=pin the selection.
kubectl add never runs kubectl apply locally. Instead it:
- Resolves the resource through pluggable transports (git, http, image), each sniffing the content to pick a format (yaml, kustomize, helm).
- Forwards your credential — the client certificate or bearer token from your kubeconfig — into a short-lived Secret, alongside the cluster CA.
- Runs a throwaway pod (
bitnami/kubectl) that applies the manifest file-less —--server,--certificate-authority, and your--token/--client-certificate— with the manifest streamed to its stdin (never persisted to etcd).
The apply runs as you: it's attributed to your identity and constrained by your own RBAC. No ServiceAccount is created and no privileges are granted.
Kustomizations are built in a second, credential-less pod and piped to the applier; the plugin binary is the pipe. Helm charts are rendered client-side with the helm SDK and the rendered manifest is applied the same way.
The apply runs with your own credential, so it can only do what you can. If it fails with a forbidden error, you lack the RBAC to apply that resource — grant it to your user, or run as one who has it. Authentication methods that can't be forwarded (some exec/OIDC setups that return a client certificate rather than a token) will error rather than silently escalate.
The values used for a chart are persisted in a ConfigMap
(kubectl-add-values-<hash>) in the target namespace, keyed by the chart URL.
The first install stores the chart's defaults; later installs reuse them. Each
install opens the ConfigMap in your editor before rendering (unless --no-edit
or a non-interactive stdin), so you can review and adjust the values.
kubectl add <resource> --verbose # -v=2 on the remote kubectl
kubectl add <resource> --debug # -v=4, plus local debug logs- Examples:
test/e2ein this repo - Issues: https://github.com/scaffoldly/kubectl-add/issues
This is open source software licensed under the MIT License. Contributions are welcome — please open an issue or pull request.