Asherah supports HashiCorp Vault's Transit secrets engine as a key management backend. Vault Transit acts as an encryption oracle — the master key never leaves Vault, and all encrypt/decrypt operations are performed server-side via Vault's API.
This is the recommended KMS backend for on-premises deployments where AWS KMS is not available.
Asherah's key hierarchy uses a system key at the top level, which is encrypted by the KMS backend. With Vault Transit:
- Asherah generates a system key (random AES-256 key)
- Asherah sends the system key to Vault Transit for encryption
- Vault encrypts it with a named key managed by Vault (the master key)
- The encrypted system key is stored in the metastore (DynamoDB, MySQL, etc.)
- On decrypt, Asherah sends the encrypted system key back to Vault
- Vault decrypts and returns the plaintext system key
The master key inside Vault is never exposed — Asherah only sees ciphertext. Vault handles key versioning, rotation, and access control.
- A running HashiCorp Vault server
- The Transit secrets engine enabled
- A named encryption key created in Transit
- An authentication method configured for your application
# Start Vault in dev mode (NOT for production)
docker run -d --name vault \
--cap-add=IPC_LOCK \
-e VAULT_DEV_ROOT_TOKEN_ID=dev-token \
-p 8200:8200 \
hashicorp/vault
# Enable Transit engine
export VAULT_ADDR=http://localhost:8200
export VAULT_TOKEN=dev-token
vault secrets enable transit
# Create a named key for Asherah
vault write transit/keys/asherah-master type=aes256-gcm96# Enable Transit (if not already enabled)
vault secrets enable transit
# Create a key with auto-rotation every 90 days
vault write transit/keys/asherah-master \
type=aes256-gcm96 \
auto_rotate_period=2160h
# Create a policy that only allows encrypt/decrypt (not key export)
vault policy write asherah-transit - <<EOF
path "transit/encrypt/asherah-master" {
capabilities = ["update"]
}
path "transit/decrypt/asherah-master" {
capabilities = ["update"]
}
EOFSet KMS=vault (or KMS=vault-transit) and provide the following environment
variables:
| Variable | Required | Description |
|---|---|---|
VAULT_ADDR |
Yes | Vault server URL (e.g., https://vault.example.com:8200) |
VAULT_TRANSIT_KEY |
Yes | Name of the Transit key (e.g., asherah-master) |
VAULT_TRANSIT_MOUNT |
No | Transit mount path (default: transit) |
Vault requires authentication to make API calls. Asherah supports four auth methods, configured via environment variables:
Set VAULT_TOKEN directly. Simple but requires a long-lived token.
export VAULT_TOKEN=hvs.CAESIJ...When to use: Development, testing, or when tokens are managed externally (e.g., injected by a deployment pipeline).
Not recommended for production — tokens can expire, and storing them in config has the same secret-zero problem as a static master key.
Pods authenticate using their service account JWT, which is automatically mounted by Kubernetes. No secrets to manage.
export VAULT_AUTH_METHOD=kubernetes
export VAULT_AUTH_ROLE=asherah-role| Variable | Required | Description |
|---|---|---|
VAULT_AUTH_METHOD |
Yes | Set to kubernetes |
VAULT_AUTH_ROLE |
Yes | Vault role name bound to the service account |
VAULT_K8S_TOKEN_PATH |
No | Path to the SA token (default: /var/run/secrets/kubernetes.io/serviceaccount/token) |
VAULT_AUTH_MOUNT |
No | Auth method mount path (default: kubernetes) |
Vault setup:
# Enable Kubernetes auth
vault auth enable kubernetes
# Configure it with the cluster's CA and API server
vault write auth/kubernetes/config \
kubernetes_host="https://kubernetes.default.svc"
# Create a role bound to a service account
vault write auth/kubernetes/role/asherah-role \
bound_service_account_names=asherah-sa \
bound_service_account_namespaces=default \
policies=asherah-transit \
ttl=1hWhen to use: Any Kubernetes deployment. This is the recommended auth method for containerized workloads. No secret zero problem — the pod's identity is its credential.
AppRole uses a role ID (public, baked into the app) and a secret ID (private, delivered at deployment time, optionally single-use).
export VAULT_AUTH_METHOD=approle
export VAULT_APPROLE_ROLE_ID=db02de05-fa39-4855-059b-67221c5c2f63
export VAULT_APPROLE_SECRET_ID=6a174c20-f6de-a53c-74d2-6018fcceff64| Variable | Required | Description |
|---|---|---|
VAULT_AUTH_METHOD |
Yes | Set to approle |
VAULT_APPROLE_ROLE_ID |
Yes | Role ID (can be baked into deployment config) |
VAULT_APPROLE_SECRET_ID |
No | Secret ID (delivered at deploy time) |
VAULT_AUTH_MOUNT |
No | Auth method mount path (default: approle) |
Vault setup:
# Enable AppRole auth
vault auth enable approle
# Create a role with the transit policy
vault write auth/approle/role/asherah \
policies=asherah-transit \
token_ttl=1h \
token_max_ttl=4h \
secret_id_ttl=10m \
secret_id_num_uses=1
# Get the role ID (bake this into your deployment)
vault read auth/approle/role/asherah/role-id
# Generate a single-use secret ID (deliver this at deploy time)
vault write -f auth/approle/role/asherah/secret-idWhen to use: CI/CD pipelines, VMs, or any environment where you can separate role ID (public) from secret ID (private, short-lived). The secret ID can be wrapped with Vault's response wrapping for additional security.
Machines authenticate using a TLS client certificate, typically issued by your organization's PKI or Active Directory Certificate Services.
export VAULT_AUTH_METHOD=cert
export VAULT_CLIENT_CERT=/etc/asherah/client.crt
export VAULT_CLIENT_KEY=/etc/asherah/client.key| Variable | Required | Description |
|---|---|---|
VAULT_AUTH_METHOD |
Yes | Set to cert |
VAULT_CLIENT_CERT |
Yes | Path to PEM-encoded client certificate |
VAULT_CLIENT_KEY |
Yes | Path to PEM-encoded private key |
VAULT_AUTH_MOUNT |
No | Auth method mount path (default: cert) |
Vault setup:
# Enable TLS cert auth
vault auth enable cert
# Register your CA certificate
vault write auth/cert/certs/asherah-machines \
display_name=asherah \
policies=asherah-transit \
certificate=@/path/to/ca.crt \
ttl=1hWhen to use: On-premises machines with certificates from AD CS or your PKI. No secret zero problem — the machine's certificate is its credential.
The Vault Transit KMS requires the vault feature flag:
[dependencies]
asherah = { version = "0.1", features = ["vault"] }The feature adds reqwest (with rustls-tls, no OpenSSL dependency) for
Vault HTTP API calls.
# Using Kubernetes auth with DynamoDB metastore
export KMS=vault
export VAULT_ADDR=https://vault.internal:8200
export VAULT_AUTH_METHOD=kubernetes
export VAULT_AUTH_ROLE=asherah-role
export VAULT_TRANSIT_KEY=asherah-master
export Metastore=dynamodb
export DDB_TABLE=EncryptionKey
export AWS_REGION=us-west-2
export SERVICE_NAME=my-service
export PRODUCT_ID=my-productVault Transit supports automatic key rotation. When a key is rotated:
- New encryptions use the latest key version
- Old ciphertexts can still be decrypted (Vault maintains all versions)
- No data migration required — Vault handles versioned decryption transparently
This is a significant advantage over the static KMS and Secrets Manager KMS, which require re-encrypting all data to rotate the master key.
To rotate the key manually:
vault write -f transit/keys/asherah-master/rotateTo enable automatic rotation:
vault write transit/keys/asherah-master auto_rotate_period=2160h # 90 days"Vault Transit encrypt request failed: connection refused"
- Verify
VAULT_ADDRis correct and Vault is reachable - Check firewall rules between your application and Vault
"Vault kubernetes auth failed: permission denied"
- Verify the service account name and namespace match the Vault role
- Check that the Kubernetes auth backend is configured with the correct cluster CA and API server URL
"Vault Transit encrypt failed: 1 error occurred: permission denied"
- The authenticated token doesn't have the
asherah-transitpolicy - Check
vault token capabilities transit/encrypt/asherah-master
"Vault Transit decrypt: blob is not valid UTF-8"
- The ciphertext in the metastore is corrupted or was encrypted by a different KMS backend. Ensure all instances use the same KMS configuration.
| Feature | Static | Secrets Manager | AWS KMS | Vault Transit |
|---|---|---|---|---|
| Intended use | Testing only | Legacy migration only | Production (AWS) | Production (on-prem) |
| Master key storage | Env var / config | AWS Secrets Manager | AWS KMS HSM | Vault server |
| Master key leaves service? | Yes (in memory) | Yes (in memory) | Never | Never |
| Master key rotation | Manual (re-encrypt SKs) | Manual (re-encrypt SKs) | Transparent | Transparent |
| IK/SK rotation | Automatic (policy-based) | Automatic (policy-based) | Automatic (policy-based) | Automatic (policy-based) |
| Per-operation audit | No | No | Yes (CloudTrail) | Yes (Vault audit) |
| Access control | None | IAM policies | IAM + key policies | Vault policies |
| Secret zero problem | Yes | No (IAM role) | No (IAM role) | Depends on auth |