Files
vault-tools/docs/vctl.md
T
unkinben 123faf8bbf
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline failed
ci/woodpecker/pr/pre-commit Pipeline was successful
Add vctl and vctx Vault token CLIs
Introduces the vault-tools monorepo: two Go CLIs that share a config file
(~/.config/vault) and token cache (~/.cache/vault) for working with multiple
Vault instances (contexts).

- add shared/ library: config parsing (vctl.yaml/config.yaml, per-context
  overrides, slash contexts), token cache (0600/0700, atomic writes, path-
  traversal guards), and a small hand-rolled Vault HTTP client (login/renew)
- add vctl: login/renew (single or --all), list, --method/--user overrides,
  no-echo password/token prompts, dynamic context completion
- add vctx: resolve a context, set VAULT_ADDR/VAULT_TOKEN/VAULT_NAMESPACE and
  exec the vault CLI, passing remaining args through untouched
- add unit tests across shared/, vctl and vctx command layers (config
  resolution, cache paths, vault client, --all iteration + error aggregation,
  vctx arg pass-through and env construction via fakeable exec/prompt seams)
- add Makefile (build/test/completions/rpm, patch|minor|major version bumps),
  nfpm RPM packaging bundling bash/zsh/fish completions for both binaries
- add Woodpecker pipelines: build/test/pre-commit on PRs, and a tag release
  that cross-compiles, builds+uploads the RPM to artifactapi, and cuts a Gitea
  release (serviceAccountName default, k8s resources on every step)
- add README, per-command docs (docs/vctl.md, docs/vctx.md), AGENTS.md and an
  example config

Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
2026-07-26 23:28:05 +10:00

4.3 KiB

vctl

vctl manages Vault tokens for multiple vault instances ("contexts"). It logs in to (or renews tokens for) one or all configured contexts and caches each resulting token under ~/.cache/vault/<context> for use by vctx and other tooling.

Synopsis

vctl login <context>      # log in to one context
vctl login --all          # log in to every configured context
vctl renew <context>      # renew one context's cached token
vctl renew --all          # renew every context that has a cached token
vctl list                 # show contexts + cached-token status
vctl version

Flags

Both login and renew accept:

Flag Default Description
--all false Operate on every configured context.
--method <m> context/config, else ldap Override the auth method (ldap, userpass, okta, radius, token).
--user <u> context/config, else $USER Override the login username.

A context name or --all is required (but not both).

Configuration

vctl reads the first of these files that exists:

  1. ~/.config/vault/vctl.yaml
  2. ~/.config/vault/config.yaml

($XDG_CONFIG_HOME is honoured in place of ~/.config.)

# ~/.config/vault/vctl.yaml
defaults:
  method: ldap          # applied to any context that doesn't set its own
  user: ben
  namespace: ""

contexts:
  sydney:
    address: https://vault.syd1.au.unkin.net

  staging/sydney:                       # slashes are allowed; they nest on disk
    address: https://vault-staging.syd1.au.unkin.net
    namespace: staging
    user: svc-ben                       # per-context override

  legacy:
    address: https://vault-legacy.example.net
    method: userpass
    path: userpass2                      # override the auth mount path (default = method)

Field resolution

For each context, every field is resolved with the chain context value → file defaults → built-in default:

  • method — built-in default ldap.
  • user — built-in default $USER.
  • namespace — no built-in default (unset means the root namespace).
  • path — the auth mount path; defaults to the resolved method.

--method / --user on the command line override the resolved values. When --method changes the method and the context did not pin an explicit path, the auth path follows the new method.

Auth methods

  • Password methods (ldap, userpass, okta, radius): vctl prompts for a password (no echo) and POSTs to auth/<path>/login/<user>.
  • token: vctl prompts for a raw Vault token (no echo), verifies it with auth/token/lookup-self, and caches its details.

Token cache

Tokens are written to ~/.cache/vault/<context> (honouring $XDG_CACHE_HOME) as JSON. Slash contexts nest: staging/sydney~/.cache/vault/staging/sydney. Parent directories are created 0700 and token files are written 0600.

Each file stores enough to inspect and later revoke the token:

{
  "context": "staging/sydney",
  "address": "https://vault-staging.syd1.au.unkin.net",
  "namespace": "staging",
  "token": "s....",
  "accessor": "hmac-...",
  "policies": ["default", "kv-read"],
  "renewable": true,
  "lease_duration_seconds": 3600,
  "issued_at": "2026-07-26T12:00:00Z",
  "expires_at": "2026-07-26T13:00:00Z"
}

The accessor lets you revoke the token later without exposing the secret (vault token revoke -accessor <accessor>).

Examples

# Log in to one context (prompts for password)
vctl login sydney

# Log in everywhere at once
vctl login --all

# Log in to a context overriding the method + user
vctl login sydney --method okta --user someone.else

# Renew a slash-named context
vctl renew staging/sydney

# Renew everything that currently has a cached token
vctl renew --all

# See what is configured and which tokens are still valid
vctl list

Shell completion

vctl completion bash > /etc/bash_completion.d/vctl
vctl completion zsh  > ~/.zsh/completions/_vctl

Context names complete dynamically from the config file (the RPM installs these completions automatically).