Add secret-store references for app-config secrets - #873
Closed
prk-Jr wants to merge 5 commits into
Closed
Conversation
Secret-bearing config fields (ec.passphrase, publisher.proxy_secret, ec.partners[].api_token, ec.partners[].ts_pull_token, handlers[].password) previously rode in the app-config blob as plaintext, so `ts config push` persisted them into the config store. Add an opt-in `[secrets]` mode where those fields instead hold secret-store key names, resolved from the platform secret store at settings load. Validation splits along the EdgeZero 3.3.8 boundary: push/deploy validates key-name shape and skips value-shape checks (a key name is not the secret); runtime resolves the references first, then runs full validation against the real values and fails closed if a referenced secret is missing or invalid. Fastly wires FastlyPlatformSecretStore into the config load path; the other adapters pass None and fail closed on store-mode blobs until wired in follow-ups. Local Viceroy secrets and a store-mode template are documented. Closes #846
Reject TRUSTED_SERVER__ secret env overrides at push/diff/validate time when store mode is enabled, so the push env overlay cannot overwrite a secret-ref key name with a plaintext value in the config blob (independent of --no-env). Omit the [secrets] section from the serialized blob whenever store mode is disabled, not only at the exact default, so inline-mode blobs stay compatible with binaries that predate the field under deny_unknown_fields. Fail closed in the resolver when a covered array section (ec.partners, handlers) is present in a non-array encoding instead of silently skipping it. Keep the partner API-token non-empty check in key-name mode and defer only the minimum-length rule. Correct the docs: the Fastly CLI reads secret values from stdin or a file (there is no --secret flag), and list every covered override including partner ts_pull_token.
prk-Jr
marked this pull request as ready for review
July 9, 2026 08:48
Store mode defers ec.partners[].api_token value checks (length, token-hash uniqueness, pull-sync consistency) from deploy time, but the runtime load path only deserialized settings and rejected placeholders without building the partner registry. A mis-seeded partner secret could let the service start and serve unrelated routes, failing only on partner-specific routes instead of failing closed at startup. Build the partner registry in settings_from_config_blob_with_secrets so resolved-value validators run at load in both inline and store mode.
Collaborator
|
Superseded by #1036 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ts config pushfrom persisting secret values in the config store: an opt-in[secrets]mode makes secret-bearing config fields hold secret-store key names, resolved from the platform secret store at settings load.Changes
crates/trusted-server-core/src/secret_refs.rsPlatformSecretStore; mirrors EdgeZerosecret_walksemantics.crates/trusted-server-core/src/settings.rs[secrets]section (enabled,store);SecretFieldModesplit;validate_secret_key_names; gate admin-password check by mode.crates/trusted-server-core/src/config.rscrates/trusted-server-core/src/config_payload.rssettings_from_config_blob_with_secretsresolves refs between envelope verify and parse; fails closed when store-mode is enabled but no secret store is wired.crates/trusted-server-core/src/ec/registry.rsfrom_config_with_secret_modedefers the API-token length check to runtime in key-name mode.crates/trusted-server-core/src/settings_data.rsOption<&dyn PlatformSecretStore>.crates/trusted-server-adapter-fastly/src/app.rsFastlyPlatformSecretStoreinto the config load path.crates/trusted-server-adapter-axum/src/app.rsNone(fail closed on store-mode; wiring is a follow-up).crates/trusted-server-core/src/lib.rssecret_refsmodule.fastly.tomlts_secretsentries forec_passphrase/proxy_secret/admin_password.trusted-server.example.tomldocs/superpowers/plans/2026-07-09-secrets-to-secret-store.mdCloses
Closes #846
Test plan
cargo test-fastly && cargo test-axum && cargo test-cloudflare && cargo test-spincargo clippy-fastly && cargo clippy-axum && cargo clippy-cloudflare && cargo clippy-cloudflare-wasm && cargo clippy-spin-native && cargo clippy-spin-wasm(1.95.0)cargo fmt --all -- --checkcargo test --manifest-path crates/trusted-server-integration-tests/Cargo.toml --test parityfastly compute serve: store-mode config booted with secrets resolved fromts_secrets(200 render); removing a secret entry fail-closed with a 500 naming the missing ref (ec.passphrase), no value leaked.Hardening note
Store-mode resolution runs before
Settingsparse; the runtime then runs full validation against the resolved values (min-length passphrase, placeholder rejection, admin-password check). A missing or invalid secret returns aConfigurationerror, which the Fastly entry point surfaces via the startup-error router (fail-closed) — nopanic!/unwrap!/expect!on the config-derived path. Push/deploy validation only checks key-name shape (non-empty, no whitespace/control chars).Checklist
unwrap()in production codelogmacros (notprintln!)ts_secretsvalues are obvious dev placeholders)