Skip to content

Repository files navigation

Vaultsmith

Vaultsmith is a web UI and HTTP API for encrypting, decrypting, and re-keying Ansible Vault values. It supports Ansible Vault 1.1 and 1.2/AES256. The Go server embeds the React frontend in the built binary.

What it does

  • Encrypt a value with a selected vault profile.
  • Decrypt an existing Ansible Vault value.
  • Re-key a value from one profile to another.
  • Copy an Ansible !vault variable snippet from the result.

The server reads vault passwords from environment variables. It does not persist submitted values or accept file uploads. Native mode uses an opaque, HTTP-only session cookie and a separate readable CSRF cookie; passwords and plaintext are not stored in browser state. Request bodies are not logged.

Application limits:

  • Encrypt input: 1 MiB of UTF-8 plaintext.
  • Decrypt and re-key input: 5 MiB of UTF-8 Vault text.
  • JSON request body: 8 MiB.

Vaultsmith empty Encrypt workbench

Vaultsmith encrypted result

Use Vaultsmith

Install with Helm

The public OCI chart is version 0.3.1:

helm upgrade --install vaultsmith \
  oci://ghcr.io/forgeplane-io/charts/vaultsmith \
  --version 0.3.1 \
  --namespace vaultsmith \
  --create-namespace \
  -f /path/to/vaultsmith-values.yaml

Use auth.mode: native for a deployed instance. The chart includes the official Valkey chart and generates its password Secret by default, so you do not need to provision Redis or Valkey separately. Native mode still requires OIDC, a CSRF Secret, a Casbin policy, and profile-password Secrets. If NetworkPolicy is enabled, allow DNS and OIDC egress explicitly; the chart adds egress to the bundled Valkey pods. Set valkey.enabled: false only when using an external Redis-compatible service, then configure auth.redis.address and its credentials.

The chart creates ClusterIP Services for Vaultsmith and Valkey. Ingress and NetworkPolicy are disabled by default. Put a maintained TLS and authentication edge in front of Vaultsmith. NetworkPolicy does not authenticate HTTP callers.

For the complete values example, policy format, edge boundary, verification steps, and rollback guidance, see docs/deployment.md.

For a source checkout, use deploy/helm/vaultsmith instead of the OCI reference and omit --version; the source chart version is maintained separately.

Authentication

Set AUTH_MODE explicitly:

Mode Use Behavior
native Protected deployments OIDC Authorization Code + PKCE, Redis-backed opaque sessions, CSRF protection, and profile-scoped Casbin authorization.
off Private local development only Skips authentication and CSRF protection.

An unset or blank mode is a startup error. Native mode does not fall back to off when OIDC, Redis, or policy loading fails. In Helm YAML, write the development value as mode: "off"; unquoted off may parse as Boolean false and is rejected.

Native mode uses the verified (iss, sub) pair as identity. Browser users authenticate with OIDC Authorization Code + PKCE and Redis-backed sessions. Machine clients can use RFC 9068 JWT Bearer access tokens whose audience is the PUBLIC_BASE_URL HTTPS origin. Client-provided identity headers are ignored. If the issuer uses a private CA, mount a PEM bundle and set OIDC_CA_FILE. Do not disable TLS verification.

HTTP API

The bundled UI keeps using the legacy operation route for this bridge release. Canonical REST routes and the legacy route share the same service behavior, limits, no-store responses, request IDs, 30-second application deadline, and admission limit. Configured CORS origins are explicit.

Method and path Purpose
GET /healthz Liveness.
GET /readyz Readiness.
GET /api/v1/session Session and CSRF bootstrap.
GET /api/v1/profiles Profiles allowed for the current user and their capabilities.
POST /api/v1/operations Encrypt, decrypt, or re-key a value.
POST /api/v1/profiles/{profileId}/encrypt Canonical encrypt route.
POST /api/v1/profiles/{profileId}/decrypt Canonical decrypt route.
POST /api/v1/rotations Canonical re-key route.
GET /.well-known/oauth-protected-resource Native-mode protected-resource metadata.
POST /mcp MCP Streamable HTTP endpoint when MCP_ENABLED=true.
GET /metrics Private admission capacity, current use, and rejection counters.
GET /auth/login Start native OIDC login.
GET /auth/callback Complete native OIDC login.
POST /auth/logout CSRF-protected logout.

Operation modes are encrypt, decrypt, and rotate (the API name for re-key). A re-key request names sourceProfileId and destinationProfileId. In native mode, session mutations require the CSRF token returned by /api/v1/session; Bearer requests do not use sessions or CSRF and require the exact operation scope. MCP is disabled by default with mcp.enabled: false / MCP_ENABLED=false.

Keep plaintext, ciphertext, passwords, cookies, and tokens out of shell history, logs, screenshots, tickets, and pull requests.

Development

Run locally

Requirements:

  • Go 1.25 or newer
  • Node.js 22 and npm
  • Bash, curl, and tar
  • Python 3.9 or newer
  • sha256sum or shasum

ansible-vault is not required at runtime. The make compatibility target requires the CLI to be installed.

Build the frontend, then start a loopback-only server in off mode:

npm ci --prefix frontend
npm run build --prefix frontend

export VAULT_PROFILES_JSON='[{"id":"dev","label":"Development","passwordEnv":"VAULT_PASSWORD_DEV"}]'
export VAULT_PASSWORD_DEV='replace-with-a-local-password'
export AUTH_MODE=off
export COOKIE_SECURE=false  # local HTTP only
export HTTP_ADDR=127.0.0.1:8080

go run ./backend/cmd/server

Open http://localhost:8080. Check the process with:

curl -fsS http://localhost:8080/healthz
curl -fsS http://localhost:8080/readyz

Never expose an off-mode server.

For frontend development, keep the Go server running and start Vite in a second terminal:

npm run dev --prefix frontend

Vite listens on http://localhost:5173 and proxies /api, /healthz, and /readyz to the Go server.

VAULT_PROFILES_JSON defines the profiles shown to the browser. Each profile refers to a separate environment variable containing its password:

[
  {
    "id": "dev",
    "label": "Development",
    "passwordEnv": "VAULT_PASSWORD_DEV"
  },
  {
    "id": "prod",
    "label": "Production",
    "passwordEnv": "VAULT_PASSWORD_PROD"
  }
]

The server rejects duplicate profile IDs, reserved environment names, missing passwords, and invalid profile metadata. Password values never appear in the profiles API.

Native integration test

The disposable harness starts Redis, Keycloak, local TLS edges, and Vaultsmith with generated credentials:

./scripts/integration-native.sh

For browser testing, keep the stack running:

./scripts/integration-native.sh --interactive

The harness removes its containers, volumes, and temporary state on exit unless KEEP_INTEGRATION_TMP=1 is set. See integration/README.md for the test flow and cleanup rules.

Checks

npm ci --prefix frontend
npm ci --prefix api/typescript-generator --ignore-scripts
npm test --prefix frontend -- --run
make typecheck
make api-check
make build
make test
make smoke
make helm-lint
make chart-test

Use SMOKE_PORT=18080 ./scripts/smoke.sh when port 8080 is busy.

See CONTRIBUTING.md for pull-request, release, and sensitive-data rules. Report vulnerabilities as described in SECURITY.md.

License

Apache License 2.0. See LICENSE.

About

Vaultsmith — a UI for encrypting, decrypting, and re-keying Ansible Vault values.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages