Skip to main content

Use a secrets manager

If your organisation already keeps passwords and keys in a secrets manager, the server can fetch them from it when it starts, so that they never sit in a file on the server. This page is for whoever runs a Node or Docker site with one of the four managers the site knows: HashiCorp Vault, AWS Secrets Manager, Doppler and Infisical.

How it works​

Set SECRETS_PROVIDER and the few variables that say where the manager is and how to log in to it. Those few have to be ordinary environment variables: they are what the server uses to reach the manager.

SECRETS_PROVIDERWhere secrets come from
env, or unsetEnvironment variables only (and NAME_FILE files). The default.
vaultHashiCorp Vault
aws-secrets-managerAWS Secrets Manager
dopplerDoppler
infisicalInfisical

Capitals in the value do not matter.

What happens at start:

  1. The server reads any NAME_FILE settings.

  2. It asks the manager for the secrets, once.

  3. It puts each one into its environment under the secret's name, so store them in the manager under the same names as the settings: ADMIN_PASSWORD, RESEND_API_KEY, DATABASE_URL.

  4. It reads NAME_FILE settings again, in case the manager supplied one.

  5. It logs how many values it took:

    [secrets] 6 value(s) loaded from vault

The rules:

  • A variable that is already set wins. The manager's value is used only where the environment has none, or has an empty one. That makes a local override easy, and it means a stale value left in a .env file hides the manager's.
  • Only upper-case names are applied. A name must start with a capital letter and contain only capitals, digits and underscores. A secret called adminPassword or admin-password is skipped silently. The count in the log line tells you how many were taken.
  • Secrets are fetched once. After changing one in the manager, restart the site.
  • The server refuses to start if the manager cannot be reached or refuses the request. A site running without its admin login and email settings would be worse than one that is down. The error follows [server] failed to start: in the log.
  • PORT and DATA_DIR cannot come from the manager. The launcher reads them before any secret is fetched.

The helper scripts (config:check, admin:add, db:migrate) fetch secrets the same way, so they need the same variables and the same network access.

HashiCorp Vault​

VariableWhat it isDefault
VAULT_ADDRThe address of the Vault server, such as https://vault.example.org:8200.none, required
VAULT_TOKENA token allowed to read the secret.none, required
VAULT_SECRET_PATHThe path of the secret, as it appears after /v1/ in Vault's HTTP API.none, required
VAULT_NAMESPACEThe namespace, for Vault Enterprise and HCP Vault.none

Every key in that one secret is fetched. Both versions of the key-value engine work, but the path differs:

  • KV version 2 has data in the path: a secret written with vault kv put secret/choir … is at secret/data/choir.
  • KV version 1 has no data: secret/choir.
SECRETS_PROVIDER=vault
VAULT_ADDR=https://vault.example.org:8200
VAULT_TOKEN=hvs.example
VAULT_SECRET_PATH=secret/data/choir

The token is used as given. The server does not log in with AppRole or another method, and does not renew the token, so give it one that is still valid whenever the site restarts.

AWS Secrets Manager​

VariableWhat it isDefault
AWS_SECRETS_MANAGER_SECRET_IDThe name or ARN of the secret.none, required
AWS_REGIONThe region the secret is in.none, required
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEYCredentials allowed secretsmanager:GetSecretValue on that secret.none, required
AWS_SESSION_TOKENThe session token, when the credentials are temporary.none

The secret must be one secret whose value is a JSON object, which is what the AWS console makes when you choose "Other type of secret" and enter key and value pairs:

{
"ADMIN_PASSWORD": "a-long-random-password",
"RESEND_API_KEY": "re_your_key"
}
SECRETS_PROVIDER=aws-secrets-manager
AWS_SECRETS_MANAGER_SECRET_ID=choir/production
AWS_REGION=ca-central-1
AWS_ACCESS_KEY_ID=AKIAEXAMPLE
AWS_SECRET_ACCESS_KEY=example

Two things to know:

  • The credentials must be given as these variables. The server does not pick them up from an instance role, a container role or a profile in ~/.aws.
  • AWS_REGION, AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are the same variables Amazon SES uses for email. If you send through SES, the same credentials and region serve both unless you give SES its own with the TRANSACTIONAL_ and ANNOUNCEMENT_ forms.

Doppler​

VariableWhat it isDefault
DOPPLER_TOKENA service token for one config.none, required

A service token belongs to one project and one config, so the token alone says which secrets to fetch. Every secret in that config is fetched.

SECRETS_PROVIDER=doppler
DOPPLER_TOKEN=dp.st.example

Infisical​

VariableWhat it isDefault
INFISICAL_TOKENA token allowed to read the secrets.none, required
INFISICAL_PROJECT_IDThe project's id.none, required
INFISICAL_ENVIRONMENTThe environment's short name, such as prod.none, required
INFISICAL_SECRET_PATHThe folder to read./
INFISICAL_URLThe address of your own Infisical server.https://app.infisical.com

Every secret in that folder is fetched. Sub-folders are not.

SECRETS_PROVIDER=infisical
INFISICAL_TOKEN=st.example
INFISICAL_PROJECT_ID=00000000-0000-0000-0000-000000000000
INFISICAL_ENVIRONMENT=prod

Check it​

node --env-file=.env scripts/check-config.js

The check fetches from the manager as the server would. Look for the [secrets] … value(s) loaded from … line above the JSON, and for (set) beside the secrets you expect. The last line of the JSON, "secrets", names the provider in use.

If something goes wrong​

What you seeCause
Unknown SECRETS_PROVIDER "…". Use env, vault, aws-secrets-manager, doppler or infisical.A misspelt value.
VAULT_ADDR, VAULT_TOKEN and VAULT_SECRET_PATH are required, and the like for the other threeOne of that manager's required variables is missing.
A status code and the manager's answer, such as 403 Forbidden: … or 404 Not Found: …The manager refused: a wrong or expired token, a wrong path, or a token without permission to read. For Vault, a 404 is often a KV version 2 path without data in it.
fetch failedThe manager could not be reached at all: a wrong address, a firewall, or a certificate Node does not trust.
[secrets] 0 value(s) loaded from …The manager answered, but nothing was taken: every name was already set in the environment, or none was in upper case.

Other managers​

For 1Password, Bitwarden Secrets Manager, Azure Key Vault, Google Secret Manager and others, use the tool's own command to start the site with the secrets in its environment, or have it write them to files: Keep secrets in files.