werk

@werk/tresor (0.1.1)

Published 2026-07-26 20:22:05 +02:00 by amelie

Installation

@werk:registry=https://gitlab.amandy.love/api/packages/werk/npm/
npm install @werk/tresor@0.1.1
"@werk/tresor": "0.1.1"

About this package

Tresor secret and credential service with CLI and daemon wrappers.

Tresor

Tresor is a standalone Rust secret service and CLI. tresord runs the HTTP service; tresor is the operator CLI for storing and using secret refs.

Architecture

tresor/
  crates/
    tresor-core/   — domain types and CredentialStore trait
    tresor-store/  — SQLite backend
    tresor-api/    — Axum HTTP server
    tresor-cli/    — operator CLI
  migrations/sqlite/

Docs

Current security status

New secret writes use owner-bound refs, version rows, audit events, and encrypted payload storage. The existing /v1/credentials/* routes remain as the Aurora Relay compatibility surface and are mapped onto the new secret storage model.

The current v1 implementation defaults to OIDC bearer-token validation and Regelwerk authorization. Legacy service tokens and allow-open modes are explicit development or compatibility modes. Production payload writes use age-v1 envelope encryption.

API (Aurora Relay contract)

All credential routes require:

  • Authorization: Bearer <OIDC access token> in production, or a legacy token only when TRESOR_AUTH_MODE=legacy-token
  • "relayId": "..." in the request body (optional, logged for audit)
Method Path Description
GET /health Liveness probe — { "ok": true }
POST /v1/credentials/check Check whether a credential ref exists
POST /v1/credentials/resolve Resolve and return a credential bundle
PUT /v1/credentials Store a legacy credential bundle

The native secret API is available under /v1/secrets:

Method Path Description
GET /v1/secrets List safe secret metadata
PUT /v1/secrets Store a new encrypted secret version
POST /v1/secrets/metadata Read safe metadata for one ref
POST /v1/secrets/use Resolve a secret for runtime use
POST /v1/secrets/read Read raw payload with secret.read
POST /v1/secrets/rotate Rotate the active secret payload
POST /v1/secrets/versions List version metadata
POST /v1/secrets/audit List audit events
DELETE /v1/secrets/delete Delete a secret

Check

POST /v1/credentials/check
{
  "credentialRef": "OCI_LOGICALIS",
  "expectedType": "oci",
  "relayId": "aurora-relay"
}

Response 200:

{ "configured": true, "kind": "oci" }

Response 404 when the ref is not stored.

Resolve

POST /v1/credentials/resolve
{
  "credentialRef": "OCI_LOGICALIS",
  "expectedType": "oci",
  "relayId": "aurora-relay",
  "actionContext": {
    "subjectId": "user-1",
    "action": "oci.execute",
    "resourceId": "ocid1.compartment.oc1..abc"
  }
}

Response 200:

{
  "leaseId": "lease-…",
  "expiresAt": "2026-07-07T18:00:00Z",
  "bundle": {
    "type": "oci",
    "data": {
      "userOcid": "…",
      "tenancyOcid": "…",
      "fingerprint": "…",
      "region": "eu-frankfurt-1",
      "privateKeyPem": "-----BEGIN PRIVATE KEY-----\n…"
    }
  }
}

Error responses

All errors return a JSON body:

{ "error": "description" }
Status When
401 Unauthorized Missing or invalid bearer token
404 Not Found Credential ref not stored
422 Unprocessable Entity Invalid credentialRef or expectedType
500 Internal Server Error Storage error

Configuration

Variable Default Description
TRESOR_BIND_ADDR 0.0.0.0:9471 HTTP listen address
TRESOR_DB_PATH .tresor/tresor.db SQLite database path
TRESOR_AUTH_MODE oidc Authentication mode: oidc, dev-open, or explicit legacy-token
TRESOR_OIDC_ISSUER OIDC issuer when TRESOR_AUTH_MODE=oidc
TRESOR_OIDC_AUDIENCE Expected JWT audience
TRESOR_OIDC_JWKS_URL <issuer>/protocol/openid-connect/certs Optional JWKS override
TRESOR_OIDC_USERNAME_CLAIM preferred_username User actor claim
TRESOR_OIDC_SERVICE_CLAIM azp Service actor claim
TRESOR_OIDC_ACTOR_REALM inferred from issuer Actor realm segment
TRESOR_SERVICE_TOKEN Legacy bearer token, only with TRESOR_AUTH_MODE=legacy-token
TRESOR_SERVICE_TOKEN_FILE File containing legacy bearer token
TRESOR_AUTHZ_MODE regelwerk Authorization mode: regelwerk or explicit dev-open
TRESOR_REGELWERK_URL Regelwerk base URL for /v1/check
TRESOR_REGELWERK_TIMEOUT_MS 1500 Regelwerk HTTP timeout
TRESOR_MIGRATIONS_DIR auto (dev: workspace-relative, Docker: /app/migrations/sqlite) SQL migrations directory
TRESOR_KEY_PROVIDER Required key provider mode: age-file or dev-file
TRESOR_AGE_RECIPIENTS_FILE age recipients used for new payload encryption
TRESOR_AGE_IDENTITY_FILE age identity used for active version decryption
TRESOR_KEY_FILE Dev-only key material file for dev-file
TRESOR_DEFAULT_REALM Realm used by native and legacy secret routes
TRESOR_LEGACY_OWNER service:tresor:legacy Owner assigned to legacy credential writes

Production should use TRESOR_KEY_PROVIDER=age-file. dev-file is only for local development and must be selected explicitly.

Build and run

cargo build --release -p tresor-api -p tresor-cli
export TRESOR_AUTH_MODE=dev-open
export TRESOR_AUTHZ_MODE=dev-open
export TRESOR_KEY_PROVIDER=dev-file
printf '0123456789abcdef0123456789abcdef\n' > /tmp/tresor-dev-key
export TRESOR_KEY_FILE=/tmp/tresor-dev-key
export TRESOR_DEFAULT_REALM=default
export TRESOR_DB_PATH=.tresor/tresor.db
cargo run -p tresor-api --bin tresord

The server shuts down gracefully on SIGTERM or Ctrl-C, draining in-flight requests before exit.

Development

Testing

# Run all workspace tests
cargo test --workspace

# Run only API integration tests
cargo test -p tresor-api

# Run with log output
RUST_LOG=debug cargo test --workspace -- --nocapture

Linting and formatting

# Check formatting
cargo fmt --all --check

# Run clippy
cargo clippy --workspace --all-targets -- -D warnings

CLI

export TRESOR_URL=http://127.0.0.1:9471
export TRESOR_OIDC_ISSUER=https://keycloak.example/realms/example
export TRESOR_OIDC_CLIENT_ID=tresor-cli
tresor login
printf '{"password":"app-password"}' | tresor secret put app/postwerk/yahoo-main --type password --owner service:postwerk --from-stdin
tresor secret list
tresor secret metadata app/postwerk/yahoo-main
tresor secret use app/postwerk/yahoo-main
tresor secret versions app/postwerk/yahoo-main

For local compatibility mode, run tresor login --legacy-token <token> against a daemon started with TRESOR_AUTH_MODE=legacy-token.

Do not pass secret values as command arguments. Use --from-stdin or --from-file.

Migration

Legacy rows from the deprecated credentials table can be imported once into owner-bound encrypted secrets:

export TRESOR_KEY_PROVIDER=age-file
export TRESOR_AGE_RECIPIENTS_FILE=/run/secrets/tresor-age-recipients
export TRESOR_AGE_IDENTITY_FILE=/run/secrets/tresor-age-identity
tresor migrate legacy-credentials --owner service:tresor:migration --realm production

The migration is idempotent: refs already present in secrets are skipped. It refuses non-age providers unless --dev-allow-insecure-key-provider is passed.

Aurora Relay integration

AURORA_CREDENTIAL_BACKEND=tresor
AURORA_TRESOR_URL=http://127.0.0.1:9471
AURORA_TRESOR_ACCESS_TOKEN_FILE=/run/secrets/aurora-relay-oidc-access-token
AURORA_RELAY_ID=aurora-relay

Security

  • private_key_pem is never included in error responses.
  • New production secret payloads are encrypted as age-v1.
  • TRESOR_ENV=production requires OIDC auth, Regelwerk authz, and age-file.
  • Regelwerk denial is fail-closed before active version reads or decryption.
  • The legacy credentials table remains read-compatible; migration imports rows into secrets and secret_versions.

Docker

docker build -t tresor:latest .
docker compose -f deploy/docker-compose.tresor.yml up
Details
npm
2026-07-26 20:22:05 +02:00
0
latest
58 KiB
Assets (1)
Versions (2) View all
0.1.1 2026-07-26
0.1.0 2026-07-26