Vault and OpenBao JWT authentication¶
The plugin can log in to HashiCorp Vault and OpenBao with a signed JWT, then keep the issued client token alive. That client-token renewal is not the same as secret rotation.
OpenBao uses the same behavior with OPENBAO_* variables instead of VAULT_*.
Plugin configuration¶
Set VAULT_AUTH_METHOD=jwt (or OPENBAO_AUTH_METHOD=jwt). You must also set a
role name and provide a JWT from the environment or a file.
| Variable | Description | Default |
|---|---|---|
VAULT_AUTH_METHOD / OPENBAO_AUTH_METHOD |
Set to jwt |
token |
VAULT_JWT_ROLE / OPENBAO_JWT_ROLE |
JWT/OIDC role name (required) | — |
VAULT_JWT / OPENBAO_JWT |
Signed JWT string | — |
VAULT_JWT_FILE / OPENBAO_JWT_FILE |
Path to a file containing the JWT | — |
VAULT_JWT_AUTH_PATH / OPENBAO_JWT_AUTH_PATH |
Auth mount path | jwt |
Either *_JWT or *_JWT_FILE is required. If both are set, the file is
used. The file is read again on every re-login, so you can rotate the identity
JWT on disk without reconfiguring the plugin. A JWT stored in *_JWT is fixed
until the next docker plugin set.
*_JWT_FILE is opened inside the plugin. The default plugin config
bind-mounts host /run/swarm-external-secrets only, so the JWT file must live
under that directory (same path on the host and in the plugin). Additional
paths work only if you ship a custom plugin with extra mounts.
Environment JWT¶
docker plugin set swarm-external-secrets:latest \
SECRETS_PROVIDER="vault" \
VAULT_ADDR="https://vault.example.com:8200" \
VAULT_AUTH_METHOD="jwt" \
VAULT_JWT_ROLE="swarm-external-secrets" \
VAULT_JWT="<signed-jwt>" \
VAULT_JWT_AUTH_PATH="jwt"
OpenBao:
docker plugin set swarm-external-secrets:latest \
SECRETS_PROVIDER="openbao" \
OPENBAO_ADDR="https://openbao.example.com:8200" \
OPENBAO_AUTH_METHOD="jwt" \
OPENBAO_JWT_ROLE="swarm-external-secrets" \
OPENBAO_JWT="<signed-jwt>" \
OPENBAO_JWT_AUTH_PATH="jwt"
JWT file¶
sudo mkdir -p /run/swarm-external-secrets
sudo install -m 0600 ./workload.jwt /run/swarm-external-secrets/workload.jwt
docker plugin set swarm-external-secrets:latest \
SECRETS_PROVIDER="vault" \
VAULT_ADDR="https://vault.example.com:8200" \
VAULT_AUTH_METHOD="jwt" \
VAULT_JWT_ROLE="swarm-external-secrets" \
VAULT_JWT_FILE="/run/swarm-external-secrets/workload.jwt"
JWT role and policy¶
Enable JWT auth and create a role whose policies can read your KV secrets. The issued token must also be allowed to renew itself:
path "secret/data/*" {
capabilities = ["read"]
}
path "secret/metadata/*" {
capabilities = ["list"]
}
path "auth/token/renew-self" {
capabilities = ["update"]
}
Current Vault and OpenBao JWT auth reject identity tokens that omit all of
iat, nbf, and exp. Include at least one (typically iat and exp) and
match iss, sub, and aud to the role (bound_issuer, bound_subject,
bound_audiences).
A full local setup used by CI is in scripts/tests/smoke-test-vault-jwt.sh and
scripts/tests/smoke-test-openbao-jwt.sh in this repository.
Client-token renewal¶
After a successful AppRole or JWT login, Vault/OpenBao returns a client token with a TTL. The plugin renews that token; it does not mint a new identity JWT.
| Auth method | Client-token renewal | Re-login when renew fails |
|---|---|---|
token |
No. A static VAULT_TOKEN / OPENBAO_TOKEN is used until it expires. |
No |
approle |
Yes | Yes (role_id / secret_id) |
jwt |
Yes | Yes (same JWT, or a freshly read *_JWT_FILE) |
When the issued token is renewable and has a positive TTL, a background worker:
- Waits until about two-thirds of the remaining lease TTL.
- Calls
auth/token/renew-self. - If renew fails (including when max TTL is reached), logs in again with AppRole or JWT.
- If a secret read returns
401or403, logs in again and retries the read.
Retries after a failed renew use a 5s wait that doubles up to one minute.
Look for these plugin log lines (vault or openbao depending on the
provider). The re-auth warning is emitted at warn level; the two success lines
are debug (LOG_LEVEL=debug or 6):
Successfully renewed vault token(debug)Renewing vault token failed, attempting re-authentication(warn)Successfully re-authenticated with vault(debug)
Static tokens do not auto-renew
VAULT_AUTH_METHOD=token (the default) never starts the renewal worker.
Use AppRole or JWT when the plugin must outlive a short-lived client token.
Secret rotation is separate
ENABLE_ROTATION watches KV values and updates Swarm secrets. Token
renewal keeps the plugin authenticated. See Secret rotation.
CI smoke tests¶
The smoke-test-jwt-renewal job in .github/workflows/smoke-tests.yml runs
the Vault and OpenBao JWT scripts with a 10s token TTL, 25s max TTL, and a 45s
wait so CI asserts both renew-self and max-TTL re-login, then redeploys a
stack to prove reads still work.