Skip to content

Bind credentials to approved contexts and add secure provisioning - #1453

Open
ChristianPavilonis wants to merge 6 commits into
mainfrom
feature/1037-secret-bindings
Open

ChristianPavilonis wants to merge 6 commits into
mainfrom
feature/1037-secret-bindings

Conversation

@ChristianPavilonis

@ChristianPavilonis ChristianPavilonis commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Bind all twelve credential roles to their purpose, actual identity, and approved endpoint or route policy. Native values stay raw; configuration has no credential labels or physical key selectors.
  • Add reviewed ts secrets plan/check/set workflows using existing deployment manifests and mappings. Secure direct writes support Fastly; all four adapters support generated native identities and provisioning instructions.
  • Migrate loading, exporters, fixtures, examples, and operator guides. This remains a draft security implementation, not a released fix.

A config-store writer can recompute the envelope checksum. Authorization therefore comes from the provisioned native lookup identity, not that checksum. Changing a credential's purpose or approved destination selects another key. Complete already-provisioned identities remain selectable, and retaining old bindings retains their authorization.

Breaking change: reprovision secrets before upgrading

After this merges, existing deployments must reprovision all required app secrets under the new generated bindings before deploying the new version. Legacy secret names will not work. Existing raw credential values can be reused; reprovisioning does not itself require rotation.

  1. Remove the old secret-reference config fields and set replacement activation flags where needed.
  2. Generate and review a ts secrets plan, then securely provision every required binding.
  3. Deploy the matching binary and config, recreate runtime state, and verify traffic before retiring legacy bindings. Keep old and new config snapshots separate during rollout.

See the full migration guide.

Changes

Files Change
crates/trusted-server-core/src/secret_bindings*.rs Shared versioned compiler, strict normalization, private resolved credentials/targets, credential validation, and native rendering
config_payload.rs, settings*.rs, config.rs Reject removed reference properties before lookup, explicit optional activation flags, atomic loading, and credential-free serialization
Core registries, pull/DataDome/S3 code; Fastly tinybird.rs Consume checked capabilities, verified-TLS/no-follow policy, final S3 route/origin/Host/method checks, and named signing region
crates/trusted-server-cli/src/commands/secrets/ Fresh reviewed-plan/resource equality before input or mutation, hidden TTY/stdin input, presence-only checks, and Fastly create/replace
Adapter startup, integration fixtures, smoke scripts, manifests Actual generated native lookups; shared-context declaration coalescing; safe native startup diagnostics; reproducible fictional fixtures
docs/guide/{secrets,secrets-ci,secret-binding-migration}.md, existing guides/examples Provisioning, protected Bash/CI input, coordinated migration, rotation/state refresh, retirement/replay, and unsafe-downgrade guidance

Compatibility and dependency

  • All twelve credential-reference properties are removed from unresolved configuration. There is no legacy credential-key or inline-value fallback.
  • Former optional credentials use ec.partners[*].api_token_enabled = false and S3 auth.session_token_enabled = false. Enabled missing credentials fail loading.
  • Same-context rotation replaces the native value. Retained states need refresh; multi-key S3 changes require overlap/maintenance because writes are not transactional.
  • The EdgeZero prerequisite is pinned to published commit 4f645b1e705d295117c93f4c74db12e5692ffb34, companion draft Support implicit credential lookup plans and shared Fastly secret operations edgezero#444. No local path patch or released-prerequisite claim.

Related issue

Refs #1037. The issue must stay open until the native security and migration gates below pass. Related design draft: #1407.

Test plan

Check Outcome
Core host library 2,967 passed
CLI library 749 passed, 9 existing ignored
Fastly/Viceroy Adapter 223 passed; core WASI 2,961 passed, 6 ignored; additional suites passed
Fastly reusable sandbox 223 passed
Axum / Cloudflare / Spin host suites 48 / 55 / 90 passed; existing doctest ignores retained
Integration parity 17 passed
Native fixture library / generator 3 / 13 passed, including complete Cloudflare/Spin TOML for equal handler contexts
Actual CLI duplicate-context regression All owner rows retained; one physical declaration per identity; merged Spin TOML parses
Local first-success smokes All four passed with fictional values: missing config, each of three required credentials independently missing, and successful publisher forwarding
WASM checks and target-matched Clippy Fastly, Cloudflare and Spin passed; all eight repository Clippy aliases passed
Build-digest tests/lint, WASM clock lint, Rust format, URL-host lint, fixture regeneration Passed; generation leaves a clean worktree
JavaScript 1,211 tests / 50 files passed; format and build passed, unchanged by review corrections
Documentation ESLint, Prettier, VitePress build, outside-docs Markdown format passed; normal Rustdoc build passed

Local runtime versions include Spin 4.1.0 and Wrangler 4.83.0/workerd. Cloudflare used worker-build 0.8.5 matching the lock, with the actual default-feature bundle. Spin warns that 4.x is outside EdgeZero's previously verified SQLite-writer range; this exact local push/read-through passed, not a general version-range certification. Local smokes exercise native lookup and ordinary HTTP forwarding, not credential-bearing HTTPS security.

Validation limits: an extra combined CLI/core/integration test invocation unified both Rustls providers and four unchanged CLI crypto tests panicked. The isolated CLI gate passed. Extra strict Rustdoc -D warnings fails on untouched private/broken intra-doc links; normal Rustdoc succeeds with those warnings. Neither extra command is claimed green. No TLS-provider or unrelated documentation cleanup was added.

Independent correctness/security, architecture, maintainability, and style reviews completed. All nine findings were addressed, followed by a correction review with no new findings. The native smokes also caught missing startup diagnostics; native stderr/console now receives only the outer error context, never the report's causes or attachments. Anonymous error responses remain generic.

Release blockers

  • Review/accept the EdgeZero prerequisite and agree the production dependency pin.
  • Execute credential-bearing valid/bad-certificate/redirect HTTPS cases on all four native runtimes, including S3 preflights and retained state.
  • Prove config-writer IAM separation from secret values, bindings, and deployment permissions.
  • Verify isolated real-provider create/replace/read-through, propagation, name/value limits, and required refresh behavior.
  • Execute protected CI provisioning and coordinated migration, retirement/replay, rotation, and downgrade rehearsals.

No real application credential was read or provisioned. No production operation, merge, or release tag was performed. Fictional local fixtures and fake provider transports do not clear these gates.

Checklist

  • Required repository test, lint, formatting, and documentation checks completed as described above
  • New behavior has regression tests and independent review
  • No real credentials committed
  • Logging follows repository conventions; native startup stderr/console exceptions are explicit and avoid full error reports
  • Native security and release evidence complete

@ChristianPavilonis
ChristianPavilonis marked this pull request as ready for review October 27, 2026 19:46
Document the selected design for issue #1037 using raw native secret
values and purpose/identity/destination-derived lookup keys.

Include the independent comparison's required normalization, CLI/native
lookup, private-construction, retirement, and send-policy amendments.
This is a design-only change; implementation and runtime proof remain.
Require explicit Spin manifest paths before secret planning and checks so native declaration validation and plan fingerprints use the selected manifest.

Let Cargo check default fixture-generator freshness while preserving explicit executable overrides. Add CLI and shell regressions for both fixes.
@ChristianPavilonis
ChristianPavilonis force-pushed the feature/1037-secret-bindings branch from c131cc7 to 67c5bee Compare October 27, 2026 20:14
vector(&mut payload, export)?;
let digest = Sha256::digest(payload);
const ALPHABET: &[u8] = b"abcdefghijklmnopqrstuvwxyz234567";
let mut encoded = String::from("ts1_");
}
let (authority, path) = rest
.find('/')
.map_or((rest, "/"), |index| (&rest[..index], &rest[index..]));
let datadome_config =
serde_json::from_value::<crate::integrations::datadome::DataDomeConfig>(raw.clone())
.map_err(|_| invalid("integrations.datadome", "invalid integration structure"))?;
let enabled = bool_value(raw, "enabled", false, "integrations.datadome.enabled")?;
let protection = bool_value(
raw,
"enable_protection",
false,
Some(value) if value.is_object() => bool_value(
value,
"enabled",
false,

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants