omni-kubeconfig

module
v0.3.4-snapshot.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 1, 2026 License: MIT

README

omni-kubeconfig

CI Release golangci-lint

Download admin kubeconfigs for every cluster on a Sidero Omni server and merge them into a single file for kubectl.

Features

  • auth — SideroV1 PGP + browser login (same flow as omnictl)
  • sync — List all Omni clusters, download OIDC admin kubeconfigs, merge into one file
  • kubeconfig — Download one cluster kubeconfig; optional --service-account for token-based access (no kubelogin)
  • update — Install the latest release (self-update) or check for updates
  • One-click install via scripts/install.sh / scripts/install.ps1 with SHA256 verification
  • Interactive update prompt when a newer stable release exists (opt-out flags available)
  • Incremental merge into existing output by default (--merge-existing); full replace with --merge-existing=false
  • Name conflicts overwrite by default; --rename-on-conflict keeps both (incoming → name-1)
  • Preserves existing current-context by default (cold starts / empty current-context still get one); --activate-context sets it to the last merged cluster
  • Backups existing output as *.bak.<timestamp> before overwrite
  • Omni API v2 compatible

Quick start

curl -fsSL https://github.com/Jubblin/omni-kubeconfig/releases/latest/download/install.sh | bash

Windows (PowerShell):

irm https://github.com/Jubblin/omni-kubeconfig/releases/latest/download/install.ps1 | iex

Installs a checksum-verified binary to ~/.local/bin (Unix) or %LOCALAPPDATA%\Programs\omni-kubeconfig (Windows). Add the directory to your PATH if prompted.

Upgrade later with omni-kubeconfig update or re-run the install script. On interactive runs, the tool checks for a newer stable release and prompts to install (disable with --no-update-check or OMNI_KUBECONFIG_SKIP_UPDATE_CHECK=1). On Unix/macOS, confirming the prompt restarts into the new binary and continues your command; otherwise restart the CLI manually after updating. update skips downloading when already on the latest release.

Install from release

Download the binary for your platform from GitHub Releases (same platforms as omnictl):

Platform Asset
macOS Intel omni-kubeconfig-darwin-amd64
macOS Apple Silicon omni-kubeconfig-darwin-arm64
Linux x86_64 omni-kubeconfig-linux-amd64
Linux arm64 omni-kubeconfig-linux-arm64
Windows x86_64 omni-kubeconfig-windows-amd64.exe

Rename to omni-kubeconfig (or omni-kubeconfig.exe on Windows) and place on your PATH. Verify with sha256sum.txt on the release page.

Install from source
git clone https://github.com/Jubblin/omni-kubeconfig.git
cd omni-kubeconfig
make install
Install with Docker
docker pull ghcr.io/jubblin/omni-kubeconfig:latest

You still need a host omniconfig (from omnictl) and kubectl + kubelogin on the machine where you run kubectl. Full container workflow: Run with Docker.

Binary Prerequisites
brew install siderolabs/tap/sidero-tools   # macOS/Linux: omnictl, kubelogin, talosctl
Usage
omni-kubeconfig auth
omni-kubeconfig sync
export KUBECONFIG=~/.kube/config
kubectl config get-contexts

See Usage and Reference below for all flags.

Run with Docker

Container images are published to GitHub Container Registry as ghcr.io/jubblin/omni-kubeconfig on every push to main (snapshot) and on vX.Y.Z release tags. GoReleaser dockers_v2 pushes an immutable sha-<commit> tag first; Trivy scans that digest, then mutable tags are promoted. docker.yml only lints the Dockerfile when it changes.

The image contains only the omni-kubeconfig binary (distroless, no shell). Mount your host Omni credentials and kube output directory; run kubectl on the host against the merged file.

Image tags
Tag When
v0.3.4-snapshot Floating latest from main for the current release line (after Trivy)
v0.3.4-snapshot.N Immutable numbered snapshot for a specific main build (after Trivy)
latest Most recent release (after Trivy)
0.1.2 Exact semver (no v prefix), after Trivy
0.1 Major.minor alias on release
sha-<commit> Immutable digest pointer (pushed before scan; safe if scan fails)
# After merging to main (release line v0.3.4)
docker pull ghcr.io/jubblin/omni-kubeconfig:v0.3.4-snapshot
docker pull ghcr.io/jubblin/omni-kubeconfig:v0.3.4-snapshot.3

# After tagging v0.1.2
docker pull ghcr.io/jubblin/omni-kubeconfig:0.1.2
docker pull ghcr.io/jubblin/omni-kubeconfig:latest
Container Prerequisites

Same as the binary install, except the CLI runs inside Docker:

  • Valid omniconfig on the host (default ~/.talos/omni/config) — typically created with omnictl on the host
  • Network access from the container to your Omni endpoint
  • kubectl and kubectl oidc-login on the host (not in the image)
Typical workflow
export OKC_IMAGE=ghcr.io/jubblin/omni-kubeconfig:latest

docker pull "$OKC_IMAGE"

# 1) Authenticate (first time or expired key)
docker run --rm -it \
  --user "$(id -u):$(id -g)" \
  -e HOME="$HOME" \
  -e BROWSER=echo \
  -v "$HOME/.talos:$HOME/.talos" \
  "$OKC_IMAGE" auth

# 2) Sync all clusters into ~/.kube/config on the host
docker run --rm -it \
  --user "$(id -u):$(id -g)" \
  -e HOME="$HOME" \
  -v "$HOME/.talos:$HOME/.talos" \
  -v "$HOME/.kube:$HOME/.kube" \
  "$OKC_IMAGE" sync

# 3) Use kubectl on the host
export KUBECONFIG="$HOME/.kube/config"
kubectl config get-contexts

Open the login URL printed during auth when using BROWSER=echo. Omit -e BROWSER=echo if your environment can open a browser from inside the container.

Always mount credentials and match the host user so PGP keys and kubeconfig files remain readable/writable:

Flag Purpose
--user "$(id -u):$(id -g)" Write keys and kubeconfig as your user (image default is distroless nonroot)
-e HOME="$HOME" Keep default paths (~/.talos/..., ~/.kube/...) aligned with mount targets
-v "$HOME/.talos:$HOME/.talos" Omniconfig + SideroV1 PGP keys (auth writes under ~/.talos/keys)
-v "$HOME/.kube:$HOME/.kube" Sync output and .bak.* backups (required for sync)
Commands
# Version / help
docker run --rm "$OKC_IMAGE" --version
docker run --rm "$OKC_IMAGE" sync --help

# Auth (re-login or force new key)
docker run --rm -it \
  --user "$(id -u):$(id -g)" -e HOME="$HOME" \
  -v "$HOME/.talos:$HOME/.talos" \
  "$OKC_IMAGE" auth --force

# Sync: dry-run, subset of clusters, custom output
docker run --rm \
  --user "$(id -u):$(id -g)" -e HOME="$HOME" \
  -v "$HOME/.talos:$HOME/.talos" -v "$HOME/.kube:$HOME/.kube" \
  "$OKC_IMAGE" sync --dry-run

docker run --rm \
  --user "$(id -u):$(id -g)" -e HOME="$HOME" \
  -v "$HOME/.talos:$HOME/.talos" -v "$HOME/.kube:$HOME/.kube" \
  "$OKC_IMAGE" sync -c prod -c staging -o "$HOME/.kube/omni-prod"

# Non-interactive service account (no browser)
docker run --rm \
  --user "$(id -u):$(id -g)" -e HOME="$HOME" \
  -e OMNI_SERVICE_ACCOUNT="$OMNI_SERVICE_ACCOUNT" \
  -v "$HOME/.talos:$HOME/.talos" -v "$HOME/.kube:$HOME/.kube" \
  "$OKC_IMAGE" sync

Override paths with flags or env vars (same as the native CLI): --omniconfig, --context, -e OMNICONFIG=..., -e SIDEROV1_KEYS_DIR=....

Volume reference
Host path Container path Purpose
~/.talos $HOME/.talos omniconfig (~/.talos/omni/config) and PGP keys (~/.talos/keys)
~/.kube $HOME/.kube Merged kubeconfig (default ~/.kube/config)
Build and run locally
make docker-build                    # cross-compile linux/amd64 binary, then image
make docker-run ARGS="--version"
make docker-run ARGS="auth"
make docker-run ARGS="sync --dry-run"

# Custom image name/tag
make docker-build IMAGE=myregistry/omni-kubeconfig IMAGE_TAG=dev
make docker-run IMAGE=myregistry/omni-kubeconfig IMAGE_TAG=dev ARGS="sync"

Development

Dev Container

Open in VS Code / Cursor → Reopen in Container. Includes Go 1.25, golangci-lint, and GitHub CLI. Your host ~/.talos directory is mounted for Omni authentication.

Local
make check       # test + lint + host build + all platform builds
make build-all   # cross-compile all omnictl platforms into bin/
make dc-check    # CI-parity checks inside dev container (recommended)
make sbom        # CycloneDX SBOM (Go modules) → dist/sbom.cyclonedx.json
make hadolint    # Lint Dockerfile
make trivy-image # Scan local image + dist/sbom-image.cyclonedx.json (after docker-build)
make test
make lint
make build
./bin/omni-kubeconfig --version

See CONTRIBUTING.md.

CI/CD
Workflow Trigger Purpose
ci.yml Push/PR to main (skips docs / .cursor-only) Test, vet, golangci-lint (v2.12.2), GoReleaser snapshot build (--skip=publish), Trivy FS vuln scan; on main calls Release
docker.yml Dockerfile path changes Hadolint + Dockerfile Trivy config scan
release.yml CI success on main; tag vX.Y.Z GoReleaser binaries + GH release + GHCR (sha- then promote after Trivy), Cosign

Dependabot updates Go modules and GitHub Actions weekly.

Releasing (maintainers)
# Ensure CHANGELOG.md is updated, then:
git tag v0.3.4
git push origin v0.3.4

GoReleaser publishes bare binaries (naming matches omnictl-*) for darwin/linux amd64+arm64 and windows amd64 only, and builds/pushes the multi-arch container image via dockers_v2. See .goreleaser.yaml.

Versioning follows Semantic Versioning — see CHANGELOG.md.

First publish to GitHub
cd omni-kubeconfig
git init -b main
git add .
git commit -m "feat: initial public release"
git remote add origin git@github.com:Jubblin/omni-kubeconfig.git
git push -u origin main
git tag v0.1.0
git push origin v0.1.0

Usage

Authenticate to Omni first (opens browser when the key is missing or expired):

omni-kubeconfig auth
omni-kubeconfig auth --force   # delete PGP key and re-login

Sync all clusters into ~/.kube/config:

omni-kubeconfig sync

Use the merged config:

export KUBECONFIG=~/.kube/config
kubectl get nodes --context <cluster-name>

On success, sync prints export KUBECONFIG=<path> when -o is not the default ~/.kube/config (disable with --print-export=false).

Service-account kubeconfig (token)

For CI or other non-interactive cluster access, mint a Kubernetes service-account kubeconfig (not an Omni API service account):

omni-kubeconfig kubeconfig \
  --service-account \
  --cluster prod \
  --user ci-deploy \
  --ttl 720h \
  -o ./prod-ci.kubeconfig \
  --merge-existing=false \
  --force

Use that file with kubectl directly (embedded token; no kubelogin). See the Omni guide.

To authenticate this tool to Omni without a browser, use an Omni service account key (OMNI_SERVICE_ACCOUNT_KEY) instead — that is separate from cluster SA kubeconfigs.

Docker

Run the same commands inside the published image; mount ~/.talos and ~/.kube, use --user "$(id -u):$(id -g)", and keep kubectl on the host. See Run with Docker.

Reference

omni-kubeconfig --help, auth --help, sync --help, kubeconfig --help, and update --help mirror this section.

Global flags
Flag Default Description
--omniconfig OMNICONFIG or ~/.talos/omni/config Path to omniconfig
--context Selected context Omni context name
--insecure-skip-tls-verify false Skip TLS verification for Omni API
--siderov1-keys-dir SIDEROV1_KEYS_DIR or ~/.talos/keys SideroV1 PGP keys directory
--no-update-check false Disable check for newer releases before running a command
--check-updates false Force update check (ignore 24h cache)
-h, --help Show help
-v, --version Semver, build metadata, Omni API level
auth flags
Flag Default Description
--force false Delete PGP key and force new browser login
sync flags
Flag Default Description
-o, --output ~/.kube/config Merged kubeconfig path
-c, --cluster all Sync only these clusters (repeatable)
--merge-existing true Load existing output and merge; false replaces with clusters synced this run
--rename-on-conflict false Rename conflicting entries instead of overwriting (default overwrites)
--activate-context false Set current-context to the last cluster merged; default preserves existing (activates on empty/--merge-existing=false cold start)
--grant-type (omitted) OIDC grant: auto, authcode, authcode-keyboard; omit for kubelogin defaults (matches omnictl)
--dry-run false List clusters only
--print-export true Print export KUBECONFIG=... when -o is not ~/.kube/config
kubeconfig flags
Flag Default Description
-o, --output ~/.kube/config Kubeconfig path
-c, --cluster (required) Omni cluster name
--service-account false Mint a Kubernetes SA token kubeconfig instead of OIDC
--user UUID v8 if omitted Token sub; kubeconfig user/context omni-{cluster}-sa-{user}
--ttl 8760h (365d) SA token TTL
--groups system:masters SA token groups
--merge-existing true Merge into existing output; false writes only this cluster
--force false Overwrite existing file when --merge-existing=false
--rename-on-conflict false Rename conflicting entries instead of overwriting
--force-context-name (SA: omni-{cluster}-sa-{user}) Override context name only
--activate-context false Set current-context to this cluster
--grant-type (omitted) OIDC grant for non-SA kubeconfigs; set explicitly when needed
--break-glass false Bypass Omni when enabled for the account
--print-export true Print export KUBECONFIG=... when -o is not ~/.kube/config
update flags
Flag Default Description
--version latest stable (if newer) Install a specific release tag (e.g. v0.3.4); latest path skips when already current
--install-dir running executable Install to this directory instead of self-replace
--check false Report if a newer stable release exists (exit 1 if outdated)

After a successful self-update, the process exits and prints a restart reminder.

Environment variables
Variable Description
OMNICONFIG Omniconfig path
OMNI_ENDPOINT Override Omni API URL
OMNI_SERVICE_ACCOUNT_KEY Base64 Omni API service account (non-interactive tool auth; also SIDERO_SERVICE_ACCOUNT_KEY)
OMNI_KUBECONFIG_SKIP_UPDATE_CHECK Set to 1 to disable update prompts/checks
SIDEROV1_KEYS_DIR PGP keys directory
BROWSER Set to echo to print login URL instead of opening a browser
Examples
BROWSER=echo omni-kubeconfig auth
omni-kubeconfig sync --dry-run
omni-kubeconfig sync -o ~/.kube/omni-prod -c prod -c staging
omni-kubeconfig sync --rename-on-conflict      # keep both on name clash (incoming → name-1)
omni-kubeconfig sync --activate-context       # set current-context to last merged cluster
omni-kubeconfig sync --merge-existing=false   # drop contexts from prior syncs not in this run
omni-kubeconfig sync --grant-type authcode-keyboard
omni-kubeconfig kubeconfig -c prod
omni-kubeconfig kubeconfig --service-account -c prod --user ci-deploy -o ./prod-ci.kubeconfig --merge-existing=false --force
curl -fsSL https://github.com/Jubblin/omni-kubeconfig/releases/latest/download/install.sh | bash
omni-kubeconfig update
omni-kubeconfig update --check
omni-kubeconfig sync --no-update-check

Troubleshooting

Error Fix
client API version mismatch Use a current release (Omni API 2)
key expired omni-kubeconfig auth or auth --force
authenticate with ... Check omniconfig URL and network
unknown command "oidc-login" Install kubectl-oidc-login
Permission denied on ~/.talos or ~/.kube in Docker Add --user "$(id -u):$(id -g)" and mount both directories
Browser does not open in container Use -e BROWSER=echo and open the printed URL on the host

How it works

  1. Connects to Omni (same client bootstrap as omnictl)
  2. sync: lists Clusters.omni.sidero.dev, downloads each OIDC admin kubeconfig, merges
  3. kubeconfig: downloads one cluster kubeconfig (OIDC, or SA token with --service-account)
  4. Merges with go-kubeconfig (into existing output when --merge-existing, default)
  5. Backs up existing output before writing

Project layout

.
├── cmd/omni-kubeconfig/    # CLI entrypoint
├── internal/omni/          # Omni client, auth, sync
├── internal/version/       # Semver metadata
├── .devcontainer/          # Dev Container spec
├── Dockerfile              # Distroless image (copies GoReleaser linux binaries from dist/)
├── .github/workflows/      # CI, Docker, and release pipelines
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── NOTICE                  # Third-party licenses
└── SECURITY.md

License

This project is licensed under the MIT License.

Dependencies include Sidero Omni client libraries under the Mozilla Public License 2.0 — see NOTICE.

Omni and Sidero Labs are trademarks of Sidero Labs, Inc. This project is community-maintained and not affiliated with Sidero Labs.

Supply chain / SBOM

Artifact Generator When
sbom.cyclonedx.json cyclonedx-gomod via GoReleaser Releases (source of truth); local make sbom
sbom-image.cyclonedx.json Trivy image scan release.yml after GHCR publish

Locally:

make sbom         # dist/sbom.cyclonedx.json (gitignored)
make hadolint
make docker-build && make trivy-image   # dist/sbom-image.cyclonedx.json

CI: ci.yml runs Trivy filesystem vuln scan (CRITICAL/HIGH, unfixed ignored). Module SBOM is not uploaded as a CI artifact — GoReleaser owns it on release. docker.yml runs Hadolint and Dockerfile config scan when the Dockerfile changes.

Releases: GoReleaser attaches sbom.cyclonedx.json to GitHub Releases. release.yml Cosign-signs that SBOM bundle, pushes ghcr.io/jubblin/omni-kubeconfig:sha-<commit>, Trivy-scans the digest, promotes mutable tags only after a clean scan, then keyless-signs the image plus container SBOM with Sigstore Cosign.

Security

See SECURITY.md. Do not commit kubeconfigs, omniconfig, or PGP keys.

Fix: CI build failure (go-api-signature / gopenpgp)

Tracking issue: #37

Symptom

After Renovate merged github.com/siderolabs/go-api-signature v0.3.13 (#26), GitHub Actions on main failed across Test, Lint, all Build matrix jobs, and Docker Build image with:

omni/client@v1.8.1/pkg/omni/resources/auth/public_key.go:66:21:
cannot use key (*gopenpgp/v2/crypto.Key) as *gopenpgp/v3/crypto.Key in pgp.NewKey
Root cause
Dependency gopenpgp API
omni/client v1.8.1 v2 (public_key.go)
go-api-signature v0.3.13 v3 (pgp.NewKey)

The two versions are incompatible until omni/client aligns with gopenpgp v3 (or go-api-signature reverts to v2).

Fix applied
  1. Pin github.com/siderolabs/go-api-signature to v0.3.12 in go.mod (v2-compatible).
  2. Block Renovate from re-bumping to v0.3.13+ via renovate.json packageRules until upstream is compatible.

Verify locally:

go build ./...
make test
Remove when

Drop the pin and Renovate rule when either:

  • github.com/siderolabs/omni/client ships a release compatible with go-api-signature v0.3.13+, or
  • go-api-signature documents a supported combination with omni/client v1.8.x.

After upgrading, run go build ./..., make test, and confirm GitHub Actions are green on main before closing the tracking issue.

Directories

Path Synopsis
cmd
omni-kubeconfig command
internal
version
Package version holds semantic version metadata for omni-kubeconfig.
Package version holds semantic version metadata for omni-kubeconfig.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL