Back to Microsandbox

Secrets

docs/sdk/rust/secrets.mdx

0.5.310.4 KB
Original Source

See Secrets for how placeholder substitution works and usage examples.

HostPattern

HostPattern is used anywhere a secret policy needs to match the destination host. Allow-list patterns decide where the real secret value may be substituted; passthrough patterns decide where the placeholder may be forwarded unchanged.

VariantBuilder methodsMatches
HostPattern::Exact("api.example.com")allow_host("api.example.com"), passthrough_host("api.example.com")That exact SNI host
HostPattern::Wildcard("*.example.com")allow_host_pattern("*.example.com"), passthrough_host_pattern("*.example.com")Hosts matching the wildcard pattern
HostPattern::Anyallow_any_host_dangerous(true), passthrough_all_hosts(true)Every host

Passthrough host patterns do not make a secret eligible for substitution. They only prevent blocking when the guest sends the placeholder to a matching host, so the request is forwarded with the placeholder unchanged.

Exact and wildcard allow-list entries are pinned to observed DNS answers. For TLS-intercepted traffic, substitution requires the TLS SNI to match the pattern and the original guest destination IP to have been returned by the sandbox DNS interceptor for a matching hostname. HostPattern::Any is the only allow-list pattern that skips this DNS-to-IP pin. Empty allow-lists are rejected by the builder and treated as deny-all by the runtime.

SecretBuilder

Builder for configuring a secret's placeholder, allowed hosts, and injection scopes. Obtained through SandboxBuilder::secret(|s| s...). Each secret maps an environment variable to a real value that is only revealed when traffic goes to an allowed host via the TLS proxy.


allow_any_host_dangerous()

rust
fn allow_any_host_dangerous(self, i_understand_the_risk: bool) -> Self

Allow substitution on any host. This means any server the guest connects to will receive the real secret - effectively disabling host-based protection. Only use this when the secret is not sensitive or the sandbox network is fully locked down.

Parameters

NameTypeDescription
i_understand_the_riskboolMust be true to take effect

allow_host()

rust
fn allow_host(self, host: impl Into<String>) -> Self

Add a host that is allowed to receive the real secret value. For TLS-intercepted traffic, the proxy matches this against the SNI (Server Name Indication) in the TLS ClientHello and verifies that the original destination IP was resolved for that host by the sandbox DNS interceptor. Can be called multiple times to allow multiple hosts.

Parameters

NameTypeDescription
hostimpl Into<String>Exact hostname (e.g. "api.openai.com")

allow_host_pattern()

rust
fn allow_host_pattern(self, pattern: impl Into<String>) -> Self

Add a wildcard host pattern. The * matches any subdomain prefix.

Parameters

NameTypeDescription
patternimpl Into<String>Wildcard pattern (e.g. "*.googleapis.com")

env()

rust
fn env(self, var: impl Into<String>) -> Self

Set the environment variable name that will hold the placeholder inside the guest. The guest sees $MSB_<var> (or a custom placeholder) - never the real value. Names must be non-empty and cannot contain = or NUL; shell-identifier syntax is not required. Required.

Parameters

NameTypeDescription
varimpl Into<String>Environment variable name (non-empty, no = or NUL)

inject_basic_auth()

rust
fn inject_basic_auth(self, enabled: bool) -> Self

Control whether Authorization: Basic <base64> credentials are decoded, substituted in the decoded user:password, and re-encoded. Orthogonal to inject_headers: this flag handles the encoded-credentials case for Basic scheme; inject_headers handles literal substitution in any header line, including non-Basic Authorization schemes (Bearer, Digest).

Parameters

NameTypeDescription
enabledboolDefault: true

inject_body()

rust
fn inject_body(self, enabled: bool) -> Self

Control whether the placeholder is replaced in the HTTP request body. When enabled on HTTP/1 requests with no body content encoding, the TLS proxy rewrites framed bodies safely: Content-Length bodies up to 16 MiB are buffered until complete and the Content-Length header is updated when the body size changes; larger fixed-length bodies are blocked rather than buffered unboundedly. Transfer-Encoding: chunked bodies are decoded and re-encoded with fresh chunk sizes. Chunk trailers are preserved; original chunk boundaries and chunk extensions are not preserved. Bodies with a non-identity Content-Encoding are forwarded unchanged. HTTP/2 DATA-frame body substitution is not supported yet; matching body placeholders are blocked instead of forwarded unchanged.

Parameters

NameTypeDescription
enabledboolDefault: false

inject_headers()

rust
fn inject_headers(self, enabled: bool) -> Self

Control whether the placeholder is replaced anywhere in HTTP headers. This is the most common injection scope - covers Authorization: Bearer $MSB_... and similar patterns.

Parameters

NameTypeDescription
enabledboolDefault: true

inject_query()

rust
fn inject_query(self, enabled: bool) -> Self

Control whether the placeholder is replaced in the URL query string (the ?key=value portion of the request line).

Parameters

NameTypeDescription
enabledboolDefault: false

placeholder()

rust
fn placeholder(self, placeholder: impl Into<String>) -> Self

Override the auto-generated placeholder string. By default, microsandbox generates $MSB_<env_var>. Use this when you need a specific format or when the placeholder must match a particular byte length. Placeholders must be non-empty, may be up to 1024 bytes, and cannot contain NUL, CR, or LF.

Parameters

NameTypeDescription
placeholderimpl Into<String>Custom placeholder string: non-empty, up to 1024 bytes, no NUL/CR/LF

require_tls_identity()

rust
fn require_tls_identity(self, enabled: bool) -> Self

When true, the secret is only substituted on TLS-intercepted connections where the proxy has verified it is performing MITM. Bypassed TLS is opaque and does not receive request-body or header substitution. Disable only if you know the traffic is safe and the connection path explicitly supports non-TLS substitution.

Parameters

NameTypeDescription
enabledboolDefault: true

on_violation()

rust
fn on_violation(
    self,
    f: impl FnOnce(ViolationActionBuilder) -> ViolationActionBuilder,
) -> Self

Configure violation behavior for this secret. This can override the sandbox-wide secret violation policy and can allow selected hosts to receive the placeholder unchanged:

rust
.secret(|s| s
    .env("API_KEY")
    .value(api_key)
    .allow_host("api.github.com")
    .on_violation(|v| {
        v.block_and_log()
         .passthrough_host("api.anthropic.com")
    })
)

Passthrough hosts do not receive the real secret value; substitution still only happens for hosts configured with allow_host() or allow_host_pattern().

If a per-secret passthrough policy does not match the request host, microsandbox falls back to the sandbox-wide secret violation action. A per-secret passthrough rule cannot weaken a stricter global default such as BlockAndTerminate.


Request validation

For intercepted HTTP traffic, each request's authority must match the TLS SNI, ignoring case and an optional port. HTTP/1 uses the Host header; observed HTTP/2 uses the :authority pseudo-header. A request that uses SNI=front.example but Host: target.example or :authority: target.example is blocked before it reaches upstream. This check is applied per request on keep-alive connections and per stream for HTTP/2 HEADERS frames.

Secret substitution is not performed inside TLS bypass streams, HTTP CONNECT tunnels, SOCKS tunnels, or plain HTTP connections. Those paths can still be constrained with network policy, and placeholder violations are enforced only where microsandbox can inspect the request bytes.


value()

rust
fn value(self, value: impl Into<String>) -> Self

Set the real secret value. This is the string that replaces the placeholder when a request reaches an allowed host. It never enters the guest VM. Required.

Parameters

NameTypeDescription
valueimpl Into<String>The actual credential or token

Shorthand

secret_env()

rust
fn secret_env(self, env_var: impl Into<String>, value: impl Into<String>, allowed_host: impl Into<String>) -> Self

Convenience method on SandboxBuilder. Equivalent to .secret(|s| s.env(env_var).value(value).allow_host(allowed_host)). Uses default injection scopes (headers enabled, body disabled).

Parameters

NameTypeDescription
env_varimpl Into<String>Environment variable name (non-empty, no = or NUL)
valueimpl Into<String>Secret value
allowed_hostimpl Into<String>Allowed destination host

Types

ViolationAction

Configured globally via NetworkBuilder::on_secret_violation() or per secret via SecretBuilder::on_violation(). Determines what happens when the guest sends a request containing a secret placeholder to a host that is not in the secret's substitution allow list.

ValueDescription
BlockSilently drop the request. The guest sees a connection reset. This is the default.
BlockAndLogDrop the request and emit a warning log on the host side.
BlockAndTerminateDrop the request, log an error, and shut down the entire sandbox.
Passthrough(Vec<HostPattern>)Forward matching hosts with the placeholder unchanged. Non-matching hosts use the default secret violation action.