Skip to main content

Secrets in a Workspace

Storing Secrets

Devsy can store named secrets locally and inject them into your workspace's lifecycle commands as environment variables. This lets you keep credentials out of your devcontainer.json, shell history, and dotenv files.

Secret values are stored using the selected backend. With the default auto backend, Devsy uses your operating system's keyring when available:

  • macOS — Keychain
  • Windows — Credential Manager
  • Linux — Secret Service (libsecret / GNOME Keyring / KWallet)

When no keyring is available (or the file backend is selected), values are kept in an age-encrypted file in the Devsy config directory instead. Either way, only non-sensitive metadata (the secret's name and timestamps) is written in plaintext. Secrets are scoped to the active context.

Creating a Secret

devsy secret set DB_PASSWORD

You will be prompted for the value without echoing it to the terminal. You can also supply the value non-interactively:

# From standard input (recommended for scripts)
printf '%s' "$MY_VALUE" | devsy secret set DB_PASSWORD --stdin

# From a file
devsy secret set TLS_KEY --from-file ./tls.key

Secret names may contain only letters, digits, and underscores, since they are used directly as environment-variable names.

Listing and Reading Secrets

devsy secret list
devsy secret get DB_PASSWORD

list never prints values. A secret whose value has been removed from the keyring out-of-band is shown with the orphaned status.

Deleting a Secret

devsy secret delete DB_PASSWORD

Using Secrets in a Workspace

Per Workspace

Reference a stored secret by name when bringing up a workspace with --secret (repeatable). By default the secret is injected as an environment variable into lifecycle commands:

devsy workspace up https://github.com/example/repo --secret DB_PASSWORD

Each --secret accepts options as NAME[,type=env|mount][,target=X]:

  • type=env (default) sets an environment variable; target overrides the variable name.
  • type=mount writes the value to a file at /run/secrets/<target> on an in-memory filesystem, matching the Docker/Podman convention. target defaults to NAME. On Kubernetes this uses an in-memory emptyDir; providers that cannot mount an in-memory filesystem reject type=mount with a clear error, so use type=env there.
# Inject under a different environment-variable name
devsy workspace up ... --secret DB_PASSWORD,target=DATABASE_PASSWORD

# Mount as a file at /run/secrets/tls.key
devsy workspace up ... --secret TLS_KEY,type=mount,target=tls.key

For all Workspaces

Bind a secret to the active context so it is injected automatically on every up, without repeating --secret:

devsy secret attach DB_PASSWORD
devsy secret detach DB_PASSWORD

Bound secret names are stored in your context configuration; deleting a context also deletes its secrets from the keyring.

If a requested or bound secret cannot be found when a workspace is created, the up fails rather than silently continuing without it.

How Secrets Are Protected

Injected secret values are masked (***) in lifecycle-hook log output, so a secret echoed by a postCreateCommand will not appear in the workspace logs. Secret values are delivered to the workspace over Devsy's encrypted agent tunnel, not embedded in any command line, so they are not exposed in process listings on the host or inside the container.

Secrets delivered with type=mount are written to an in-memory tmpfs at /run/secrets, so they are never persisted to a container image layer or to disk.

Choosing a Storage Backend

Devsy supports two backends for secret values:

  • keyring — the OS keyring (Keychain / Credential Manager / libsecret).
  • file — an age-encrypted file (secrets.enc) stored alongside the Devsy config.

By default the backend is auto: Devsy uses the keyring when one is available and falls back to the encrypted file otherwise.

The file backend works with no configuration: Devsy generates and manages an encryption key for you (stored in the OS keyring when available, otherwise in secrets.key next to secrets.enc, mode 0600). This protects secrets from accidental disclosure and casual inspection, but a key stored in secrets.key offers no protection against someone who can read your Devsy config directory (they have both the key and the ciphertext). For stronger at-rest protection — for example against a stolen backup — set a passphrase (see below), which is never written to disk.

Set a persistent preference per context with the SECRETS_BACKEND option:

devsy context set -o SECRETS_BACKEND=file

Allowed values are auto, keyring, and file. To override the preference for a single command, set the DEVSY_SECRETS_BACKEND environment variable, which takes precedence over the context option.

Headless and CI Environments

When the file backend is used (either by preference or because no OS keyring is available, for example on headless Linux, containers, or CI), Devsy uses an auto-generated key by default, so no setup is required. For at-rest protection against a stolen backup or disk, set a passphrase — the encryption key is then derived from it and never stored:

export DEVSY_SECRETS_PASSPHRASE="…"
devsy secret set DEPLOY_TOKEN --stdin < token.txt

The key source (auto-generated vs. passphrase) is recorded with your secrets. If you later change it — for example by setting a passphrase for secrets that were stored with an auto-generated key — Devsy reports a clear error rather than failing to decrypt. Restore the original setting, or re-create the secrets under the new one.

Managed Environment Variables

For non-sensitive configuration you can store managed environment variables with devsy env. They share the same per-context store as secrets, but their values are kept in plaintext in the Devsy config directory (no keyring, no encryption) and are freely readable:

devsy env set LOG_LEVEL=debug
devsy env set REGION --value us-east-1
devsy env list
devsy env get LOG_LEVEL
devsy env delete LOG_LEVEL

Inject them into a workspace with --env (repeatable), optionally remapping the variable name with NAME=TARGET:

devsy workspace up ... --env LOG_LEVEL --env REGION=AWS_REGION

Use devsy secret (not devsy env) for anything sensitive: secrets are stored in the OS keyring or an encrypted file, masked in logs, and delivered over the agent tunnel.