omni-kubeconfig

module
v0.2.0-snapshot.6 Latest Latest
Warning

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

Go to latest
Published: Jul 17, 2026 License: MIT

README

omni-kubeconfig

CI Docker Release Go Report Card

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 kubeconfigs, merge into one file
  • 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

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.2.0-snapshot Floating latest from main for the current release line (after Trivy)
v0.2.0-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.2.0)
docker pull ghcr.io/jubblin/omni-kubeconfig:v0.2.0-snapshot
docker pull ghcr.io/jubblin/omni-kubeconfig:v0.2.0-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, lint, 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.1.0
git push origin v0.1.0

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).

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, and sync --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
-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 auto OIDC grant: auto, authcode, authcode-keyboard
--dry-run false List clusters only
--print-export true Print export KUBECONFIG=... when -o is not ~/.kube/config
Environment variables
Variable Description
OMNICONFIG Omniconfig path
OMNI_ENDPOINT Override Omni API URL
OMNI_SERVICE_ACCOUNT Base64 service account (non-interactive)
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

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. Lists Clusters.omni.sidero.dev resources
  3. Downloads each cluster kubeconfig via the management API
  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