Skip to main content

Workflows secrets: KeePass

Wire KeePass-backed secrets into Loom workflows using keepass:// references. Loom resolves entries from local encrypted .kdbx databases at execution time — no external service or network access required.

Prerequisites

  • A KeePass vault created through the Loom CLI (loom secrets keepass vault create).
  • Runtime environment variables configured for the vault alias (see Runtime configuration below).
  • At least one entry stored in the vault.

If you have not set up a KeePass vault yet, follow Getting started with secrets — Option B: KeePass.

Example job

This deployment example uses placeholder URLs. Replace them with your service endpoints before running it. The walkthrough below uses a local file check.

deploy:
stage: ci
target: linux
secrets:
DATABASE_PASSWORD:
ref: keepass://local/main#services/loom/deploy:password
file: true
required: true
API_TOKEN:
ref: keepass://local/main#services/loom/deploy:token
file: false
script:
- echo "Deploying with credentials..."
- curl -u "admin:$(cat "$DATABASE_PASSWORD")" https://db.example.com/health

DATABASE_PASSWORD is file-injected (default) — the variable holds a temp-file path, so the script reads the value with cat. API_TOKEN uses direct injection (file: false) and is available as a raw environment variable.

URI anatomy

keepass://<database-alias>#<entry-path>:<field>
└──────┬────────┘ └─────┬─────┘ └──┬──┘
alias from env KeePass group/ field to
var config item path read
SegmentDescriptionExample
<database-alias>Alias configured via LOOM_KEEPASS_DB_* environment variables. Maps to a .kdbx file path and unlock credentials.local/main
<entry-path>Group and item path inside the KeePass database, using / as separators.services/loom/deploy
<field>Field name to read from the entry.password, username, token

Full example: keepass://local/main#services/loom/deploy:password resolves the password field from the entry at services/loom/deploy in the database aliased as local/main.

Runtime configuration

Loom maps each database alias to a set of environment variables. For an alias like local, the variables follow this pattern:

VariablePurposeRequired
LOOM_KEEPASS_DB_LOCAL_PATHAbsolute path to the .kdbx fileYes
LOOM_KEEPASS_DB_LOCAL_PASSWORD_ENVName of the env var containing the master passwordOne of password or keyfile required
LOOM_KEEPASS_DB_LOCAL_KEYFILE_ENVName of the env var containing the path to the keyfileOne of password or keyfile required

The alias name is uppercased and delimiters are replaced with underscores. For alias local/main, the variable prefix is LOOM_KEEPASS_DB_LOCAL_MAIN_.

Minimal setup example:

export LOOM_KEEPASS_DB_LOCAL_MAIN_PATH="$PWD/.loom/keepass/LOCAL_MAIN.kdbx"
export LOOM_KEEPASS_DB_LOCAL_MAIN_PASSWORD_ENV="KEEPASS_PASSWORD"
export KEEPASS_PASSWORD="your-master-password"
tip

Store these exports in a local .env file excluded from version control and source it at the start of each session.

Script behavior by injection mode

file: true (default) — the variable holds a file path:

DB_PASS=$(cat "$DATABASE_PASSWORD")
curl -u "admin:${DB_PASS}" https://db.example.com/health

file: false — the variable holds the raw value:

echo "machine api.example.com password ${API_TOKEN}" >> ~/.netrc

Prefer file: true unless your tool requires a direct environment value. Loom sets the job variable to a temporary file path and restricts the file to 0600 permissions. This reduces exposure through environment inspection and commands that use only the path. The protection depends on those permissions and Loom's temporary-file cleanup: a tool that reads the contents into a shell trace, process argument, log, or artifact can still expose the value.

Complete walkthrough

From vault creation to a successful workflow run:

1. Create the vault (if not already done):

export KEEPASS_PASSWORD="pick-a-strong-master-password"

loom secrets keepass vault create \
--vault-path local/main \
--password-from-env KEEPASS_PASSWORD

2. Configure access and store a secret:

export LOOM_KEEPASS_DB_LOCAL_MAIN_PATH="$PWD/.loom/keepass/LOCAL_MAIN.kdbx"
export LOOM_KEEPASS_DB_LOCAL_MAIN_PASSWORD_ENV="KEEPASS_PASSWORD"
export DEPLOY_TOKEN_VALUE="tok_example_abc123"

loom secrets keepass item create \
--vault-path local/main \
--item-path services/loom/deploy \
--field token \
--value-from-env DEPLOY_TOKEN_VALUE

3. Check the entry metadata:

loom secrets keepass item list --vault-path local/main

The environment mapping in step 2 is required for item commands and workflow runs; vault creation does not save it.

4. Save this as .loom/workflow.yml:

version: v1
stages: [ci]

check-secret:
stage: ci
target: linux
secrets:
DEPLOY_TOKEN:
ref: keepass://local/main#services/loom/deploy:token
script:
- test -r "$DEPLOY_TOKEN" && test -s "$DEPLOY_TOKEN"
- echo "Secret file is readable and non-empty"

5. Validate and run:

loom check validates structure; the run resolves the secret. The script should print Secret file is readable and non-empty and the run should exit with status 0.

loom check
loom run --local --workflow .loom/workflow.yml

Safety checklist

  • Keep vault unlock credentials (master password, keyfile path) out of workflow YAML — supply them through runtime environment variables only.
  • Prefer file: true for lower leakage risk.
  • Avoid CI_DEBUG_TRACE=true when any secret uses file: false.
  • Restrict filesystem permissions on .kdbx files and keyfiles (chmod 600).
  • Validate with loom check before running.

Troubleshooting

SymptomLikely causeFix
SECRETS_PROVIDER_UNAVAILABLEMissing or incorrect LOOM_KEEPASS_DB_* env vars, or the .kdbx file path is wrongVerify all alias env vars are exported and the .kdbx file exists at the configured path
SECRETS_REF_NOT_FOUNDEntry path or field name does not match vault contentsList entries with loom secrets keepass item list and confirm the path and field
SECRETS_REF_INVALIDMalformed keepass:// URI (missing #, :, or alias)Check URI format: keepass://<alias>#<path>:<field>
SECRETS_REQUIRED_MISSINGRequired secret could not be resolved and required is true (default)Fix the provider config, or set required: false if the secret is optional
Script gets a file path instead of a valuefile: true (default) but script expects raw valueUse cat "$VAR" in the script, or set file: false on the secret