How can I source Opscotch environment variables from an external secrets source
Opscotch 3.1.1 adds OPSCOTCH_SECRETS_FROM, a startup-time way to load environment-variable values from an external source.
This is intentionally much narrower than a full secret-manager integration. The runtime reads a single blob once at startup, parses it as environment-style properties, and uses matching keys to override environment-variable lookups and bootstrap ${VAR} substitutions.
If OPSCOTCH_SECRETS_FROM is set, the external-secrets loader initializes before the rest of startup environment access happens.
The loader then:
- Reads one source.
- Parses the content as a properties file such as
KEY=value. - Records the available keys.
- Uses those values when Opscotch later asks for environment variables.
This means you can keep sensitive values out of the process environment while still letting Opscotch resolve them through its normal environment-variable paths.
Supported Source Formats
The source must be a URI-like string with one of these protocols:
file:/path/to/secrets.propertiesdevice:/path/to/secrets.propertieshttp://host/pathhttps://host/path
In the current implementation:
file:anddevice:are both treated as file reads.http:andhttps:are fetched with a simple HTTPGET.- Unsupported protocols fail startup.
Example:
export OPSCOTCH_SECRETS_FROM='file:/run/secrets/opscotch.env'
Related Environment Variables in 3.1.1
The 3.1.1 release also added or expanded several startup environment-variable paths that interact with bootstrap loading:
OPSCOTCH_BOOTSTRAP: supply the bootstrap payload from an environment variable instead of a positional argumentOPSCOTCH_BOOTSTRAP_PRIVATEKEY: supply the bootstrap private key from an environment variableOPSCOTCH_BOOTSTRAP_SECRETKEY: supply the decryption key material for encrypted bootstrap payloadsOPSCOTCH_STRING_SECRETKEYS: provide string decryption keys used by runtime string decryption paths
Those are separate features from OPSCOTCH_SECRETS_FROM, but they can also be supplied through the external-secrets blob when you want Opscotch to resolve them at startup.
Blob Format
The blob must contain environment variable like properties in KEY=VALUE format such as:
OPSCOTCH_BOOTSTRAP_SECRETKEY=senderPublicKeyHex/recipientPrivateKeyHex
OPSCOTCH_STRING_SECRETKEYS=key1,key2,key3
...
This is not a JSON API contract. The loader does not expect Vault JSON, AWS Secrets Manager JSON, or any other provider-specific response shape. If you use HTTP(S), the response body still needs to be properties-format content.
What Gets Overridden
There are two important places where the loaded values are used.
1. Environment-variable lookup
When Opscotch reads an environment variable through, an external secret with the same key wins over the direct environment value.
2. Bootstrap ${VAR} substitution
When bootstrap content is processed, environment values are merged with external-secret values and substitutes ${NAME} placeholders.
External secrets take precedence here too.
Practical Example
Suppose you want to keep the bootstrap decryption key outside the shell environment:
OPSCOTCH_BOOTSTRAP_SECRETKEY=senderPublicKeyHex/recipientPrivateKeyHex
export OPSCOTCH_SECRETS_FROM='file:/run/secrets/opscotch.env'
When Opscotch later asks for OPSCOTCH_BOOTSTRAP_SECRETKEY, it will receive the value from the external secrets blob.
The same pattern works for other Opscotch environment variables, including values used during bootstrap substitution.
Limits and Timeouts
Two optional environment variables control how the source is read:
OPSCOTCH_SECRETS_FROM_MAX_BLOB_SIZEOPSCOTCH_SECRETS_FROM_READ_TIMEOUT
Defaults in the current implementation:
- max blob size:
1048576bytes - read timeout:
10000milliseconds
Example:
export OPSCOTCH_SECRETS_FROM='https://secrets.internal/opscotch.env'
export OPSCOTCH_SECRETS_FROM_MAX_BLOB_SIZE='65536'
export OPSCOTCH_SECRETS_FROM_READ_TIMEOUT='5000'
What It Does Not Do
OPSCOTCH_SECRETS_FROM does not currently provide:
- provider-specific authentication configuration
- custom HTTP headers
- POST requests
- automatic refresh or rotation
- polling or reloading after startup
- secret selection from nested JSON payloads
For HTTP(S), the runtime performs a plain GET and expects a properties-format response body.
Failure Modes
The implementation defines four external-secret error paths:
ES1: invalid config such as unsupported protocol, malformed source, or invalid numeric limitsES2: read failure, missing file, I/O failure, or non-2xx HTTP statusES3: read timeoutES4: invalid properties blob or blob exceeding the configured max size
If the source cannot be loaded successfully, startup fails rather than silently continuing with a partially loaded blob.
Related Bootstrap Errors
The same 3.1.1 startup path also introduced bootstrap errors:
BL10: missing environment variables during bootstrap substitutionBL11: encrypted bootstrap decryption key missing, typicallyOPSCOTCH_BOOTSTRAP_SECRETKEY
These are not OPSCOTCH_SECRETS_FROM errors themselves, but they are part of the same startup/bootstrap configuration area covered by the 3.1.1 release notes.
When to Use It
Use OPSCOTCH_SECRETS_FROM when you want Opscotch to resolve sensitive environment-variable values from a file, device path, or simple HTTP(S) endpoint at startup.
Do not describe it as a general secret-manager integration layer. In the current codebase it is a single-source, startup-only properties loader that overrides environment-variable resolution for matching keys.