Secrets in a Workspace
Devsy can inject sensitive values into workspaces without placing plaintext
credentials in devcontainer.json, command-line arguments, or ordinary dotenv
files.
Secrets can come from two places:
- Devsy-managed secrets — values owned by Devsy and stored in the operating system keyring or Devsy's encrypted local file.
- External secret sources — values owned by another system, such as a SOPS-encrypted file. Devsy resolves these values when they are needed and does not import them into the local Devsy secret store.
Both use the same protected workspace delivery paths: lifecycle environment
variables, in-memory files under /run/secrets, and supported build-secret
mechanisms.
Devsy-Managed Secrets
With the default auto storage backend, Devsy stores sensitive values in your
operating system's keyring when one is available:
- macOS — Keychain
- Windows — Credential Manager
- Linux — Secret Service (libsecret / GNOME Keyring / KWallet)
When no keyring is available, or when the file backend is selected, Devsy
stores values in an age-encrypted secrets.enc file in the Devsy config
directory. Only non-sensitive metadata such as names and timestamps is written
in plaintext. Devsy-managed secrets are scoped to the active
context.
Creating a Secret
# Interactive input; the value is not echoed.
devsy secret set DB_PASSWORD
# Standard input is recommended for scripts.
printf '%s' "$MY_VALUE" | devsy secret set DB_PASSWORD --stdin
# Or read a value from a file.
devsy secret set TLS_KEY --from-file ./tls.keyListing, Reading, and Deleting
devsy secret list
devsy secret get DB_PASSWORD
devsy secret delete DB_PASSWORDdevsy secret list never prints values. A value removed from the OS keyring
outside Devsy is shown as orphaned.
External Secret Sources
An external secret source lets Devsy resolve a value at workspace startup without making Devsy a second source of truth for that value.
SOPS
Devsy supports SOPS-encrypted YAML, JSON, and
dotenv files. Devsy uses the SOPS Go implementation; installing a
sops executable is not required.
SOPS source documents use flat top-level key/value pairs in the initial implementation:
DATABASE_PASSWORD: ENC[...]
API_TOKEN: ENC[...]Registering a Local SOPS Source
If the encrypted file is already available on the machine running Devsy, add a named source:
devsy secret source add sops project ./secrets.enc.yamlDevsy validates that the file can be decrypted before saving the source. The
configuration stores the source name, type, file path, and (when set via
--format) the document format override only. Decrypted values are not
copied into the keyring or Devsy's secrets.enc file.
List or remove locally registered sources with:
devsy secret source list
devsy secret source remove projectA source cannot be removed while context-level secret bindings still reference it.
Repository-Owned SOPS Sources
A repository can declare SOPS sources in either the root-level .devcontainer.json or .devcontainer/devcontainer.json layout under customizations.devsy.secretSources.
project/
├── .devcontainer/
│ └── devcontainer.json
└── secrets.enc.yamlExample devcontainer.json:
{
"name": "My Project",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"customizations": {
"devsy": {
"secretSources": [
{
"name": "project",
"type": "sops",
"path": "./secrets.enc.yaml"
}
],
"secrets": [
"sops:project/DATABASE_PASSWORD"
]
}
}
}Repository source paths are resolved relative to the repository root. Devsy rejects paths, including symlink targets, that escape the repository root.
Repository-owned sources work with a local checkout:
devsy workspace up .and with a remote Git source:
devsy workspace up https://github.com/acme/projectFor a remote source Devsy first acquires repository data to read the requested Git
revision, then reads customizations.devsy from the effective Dev Container
configuration and the referenced encrypted SOPS files from that same revision.
Bootstrap Authentication for Private Repositories
Credentials needed to acquire a private repository must be available before Devsy can inspect repository-owned SOPS files.
For example, this is valid:
local Devsy secret / Git credential / SSH agent
│
▼
authenticate repository clone
│
▼
repository SOPS runtime secretsA repository-owned SOPS secret cannot authenticate the clone of the same repository that contains it.
--git-token may reference a Devsy-managed secret or another external source
that is already locally available before repository acquisition.
Referencing Secrets
An unqualified name continues to mean a Devsy-managed local secret:
DB_PASSWORDAn external source uses a source-qualified reference:
sops:project/DB_PASSWORDDevsy does not search other sources if a reference cannot be resolved. Explicit source selection prevents one source from silently shadowing another.
Lifecycle Environment Variables
--secret is repeatable. By default, Devsy exposes the requested value as an
environment variable to lifecycle commands:
devsy workspace up . --secret DB_PASSWORD
devsy workspace up . --secret sops:project/DATABASE_PASSWORDUse target= to change the environment-variable name:
devsy workspace up . \
--secret sops:project/DATABASE_PASSWORD,target=DB_PASSWORDMounted Secret Files
Use type=mount to write the secret to the existing in-memory secret mount:
devsy workspace up . \
--secret sops:project/TLS_KEY,type=mount,target=tls.keyThe value is available at:
/run/secrets/tls.keyProviders that cannot offer an in-memory secret mount reject type=mount with an error.
Build Secrets
Source-qualified references can also be used with Devsy's existing build-secret path:
devsy workspace up . --build-secret sops:project/NPM_TOKENThe build secret ID is the secret key (NPM_TOKEN), not the complete
source-qualified reference. Builds continue to consume it through the existing
BuildKit secret mechanism, for example:
RUN --mount=type=secret,id=NPM_TOKEN ...Attaching a Secret to a Context
Attach a locally available secret reference to the active context so it is
injected on every workspace up:
devsy secret attach DB_PASSWORD
devsy secret attach sops:project/API_TOKENDetach it with:
devsy secret detach DB_PASSWORD
devsy secret detach sops:project/API_TOKENDevsy stores only the reference for an external secret. Repository-owned
customizations.devsy can declare project-specific automatic
bindings with its secrets list. If any requested or attached value cannot be
resolved, workspace up fails rather than silently starting without it.
SOPS Credential Discovery
Devsy delegates key and KMS credential discovery to SOPS instead of creating a parallel credential system.
For age-encrypted files, normal SOPS mechanisms apply, including
SOPS_AGE_KEY, SOPS_AGE_KEY_FILE, and the standard SOPS age-key location.
For example:
export SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/keys.txt"
devsy workspace up .For AWS KMS, GCP KMS, Azure Key Vault, PGP, and other key services supported by SOPS, use the same credentials and key configuration you would use with SOPS itself.
How Secrets Are Protected
Devsy workspaces protect sensitive values by:
- Decrypting SOPS sources in memory at workspace startup without persisting plaintext to disk
- Injecting secrets directly as environment variables or memory-backed files under
/run/secrets - Redacting known secret values from logs and terminal outputs
- Excluding secret values from client-server transport and workspace metadata
Choosing a Devsy Storage Backend
For Devsy-managed values, use the supported backends:
keyring— the OS keyring (Keychain / Credential Manager / libsecret).file— an age-encryptedsecrets.encstored alongside the Devsy config.auto— use the keyring when available and otherwise fall back tofile.
Set a persistent preference per context with:
devsy context set -o SECRETS_BACKEND=fileOr override it for one command with DEVSY_SECRETS_BACKEND.
The local file backend generates and manages an encryption key automatically.
For stronger at-rest protection, set a passphrase with
DEVSY_SECRETS_PASSPHRASE; the derived encryption key is then not stored on
disk.
Managed Environment Variables
For non-sensitive configuration, devsy env stores managed environment
variables in plaintext Devsy configuration:
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_LEVELInject them with:
devsy workspace up ... --env LOG_LEVEL --env REGION=AWS_REGIONUse devsy secret or an external secret source for sensitive values. --env
is deliberately restricted to non-sensitive Devsy-managed values because that
path is not the protected secret-delivery channel.