Skip to content
SHC Docs

Vault module

SHC’s vault provides encrypted secrets storage with support for multiple providers.

  • Fernet (AES-128 + HMAC)
  • PBKDF2 key derivation with 480,000 iterations
  • User-provided vault password

Path depth determines scope:

  • {tenant}/{secret} → tenant scope (2 levels)
  • {tenant}/{stack}/{secret} → stack scope (3 levels)
  • {tenant}/envs/{environment}/{secret} → environment scope (4 levels)
  • {tenant}/{stack}/{environment}/{secret} → deployment scope (4 levels)

Resolution order (specific to general):

  1. Deployment (tenant + stack + environment)
  2. Stack (tenant + stack)
  3. Environment (tenant + environment)
  4. Tenant

Note: “system” is a tenant, not a special scope. “envs” is reserved and cannot be used as a stack name.

In config files:

database:
password: !ref+vault://db_password
smtp:
api_key: !ref+env://SMTP_API_KEY?default=test-key

Supported providers:

ProviderConfig KeyRequired SettingsTransport
Built-in encrypted databaselocal (default)vault.passwordDatabase
Pass (password-store)passNone (uses ~/.password-store)CLI (apt)
SOPSsopsfile_pathCLI
Dopplerdopplertoken, project, configHTTP
Infisicalinfisicalclient_id, client_secret, project_id, environmentHTTP
1Password Connect1passwordconnect_host, connect_token, vault_uuidHTTP
HashiCorp Vaulthashicorpaddress, token or role_id/secret_idHTTP/SDK
AWS Secrets ManagerawsregionSDK (boto3)
Azure Key Vaultazurevault_urlSDK
Google Secret Managergcpproject_idSDK
Bitwarden Secrets Managerbitwardenaccess_token, organization_idSDK

Configure per scope in config.yaml:

vault:
provider: aws
aws:
region: us-east-1
# Or use multiple providers
vault:
provider: doppler # default
providers:
doppler:
token: dop_...
project: myproject
config: prod
sops:
file_path: /etc/shc/secrets.yaml
age_key_file: /etc/shc/age.key

Vault providers can reference secrets from other providers in their configuration. This enables bootstrapping complex setups where credentials for one provider are stored in another.

vault:
providers:
# Pass has no dependencies - initialized first
pass:
gpg_id: ABCD1234
# AWS credentials stored in pass
aws:
region: us-east-1
access_key_id: ref+vault://aws_access_key
secret_access_key: ref+vault://aws_secret_key
# HashiCorp token from pass or aws
hashicorp:
address: https://vault.example.com
token: ref+vault://hc_token

Resolution algorithm:

  1. Providers with no vault refs are initialized first
  2. Remaining providers are iteratively resolved using already-resolved ones
  3. Process continues until all resolved or no progress (circular/missing deps)

Vault paths follow scoping rules (tenant/stack/secret), not provider names. Auto-resolution tries all resolved providers in order until one succeeds.

Explicit provider (discouraged): ref+vault://secret?provider=pass targets specific provider via query param.

Export format (.vlt):

{
"version": "1",
"encrypted": true,
"secrets": {
"db_password": "Z0FBQUFCYWJjMTIz..."
}
}