From 45e6bf6996bcd9724000f7005c75c073b7fe0300 Mon Sep 17 00:00:00 2001 From: Anthony Ronning <101225832+AnthonyRonning@users.noreply.github.com> Date: Thu, 23 Jul 2026 07:56:46 +0000 Subject: [PATCH 1/3] Pin Sigstore-enforcing OpenSecret SDK --- .env.example | 3 ++- CLAUDE.md | 31 ++++++++++++++++++++++++++++- Cargo.lock | 3 +-- Cargo.toml | 8 +++++++- README.md | 55 +++++++++++++++++++++++++++++++++++++++++++++++----- justfile | 3 ++- 6 files changed, 92 insertions(+), 11 deletions(-) diff --git a/.env.example b/.env.example index b94479e..7ec20e7 100644 --- a/.env.example +++ b/.env.example @@ -8,7 +8,8 @@ MAPLE_PORT=8080 # Maple Backend Configuration # Production: https://enclave.trymaple.ai # Development: https://enclave.secretgpt.ai -# Local: http://localhost:3000 +# Local: use `just run-local`; plain HTTP mock attestation is compile-time +# gated and is never enabled in release, Docker, or embedded Maple builds. MAPLE_BACKEND_URL=https://enclave.trymaple.ai # Authentication diff --git a/CLAUDE.md b/CLAUDE.md index 4ea10ad..4d9acb3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -55,11 +55,40 @@ Maple Proxy is a lightweight OpenAI-compatible proxy server that forwards reques - Handles streaming responses for chat completions - Transforms responses to OpenAI format +### TEE attestation boundary + +TEE measurement authorization is owned by the OpenSecret SDK. Maple Proxy +should only call `perform_attestation_handshake`; do not add a proxy-specific +PCR allowlist or Sigstore/Rekor verifier. + +The intended SDK handshake authenticates the AWS Nitro attestation document, +compares the complete PCR0/PCR1/PCR2 tuple with a release snapshot embedded in +the SDK, and only then accepts the enclave public key and performs key exchange. +There is no runtime Sigstore/Rekor or release-metadata network lookup. At SDK +update time, the updater verifies the release manifest and Cosign bundle, +including the expected signing identity and Rekor evidence, before generating +the embedded snapshot. + +Mock attestation is available only through the explicitly named +`insecure-local-mock-attestation` Cargo feature. Keep it disabled in release, +Docker, and embedded Maple builds; only `just run-local` opts in. + +Rekor supplies tamper-evident transparency-log evidence for the signed release +statement used to generate that snapshot. It does not itself prove Nix +reproducibility, release freshness, rollback prevention, or revocation. + +This integration branch pins an exact reviewed SDK commit with default features +disabled. That staging commit deliberately contains an empty release snapshot, +so remote handshakes fail closed. Before release, replace the pin with a +snapshot-bearing reviewed commit or published crate; do not invent an +unpublished version or vendor the SDK here. + ### Request Flow 1. Client sends OpenAI-compatible request to proxy 2. Proxy extracts API key (from header or default config) -3. Creates OpenSecret client and performs TEE attestation +3. Creates an OpenSecret client and delegates TEE authentication, release + authorization, and key exchange to the SDK 4. Forwards request to Maple backend (enclave.trymaple.ai or configured URL) 5. Streams response back to client in OpenAI format diff --git a/Cargo.lock b/Cargo.lock index 4eddf78..91cda4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1638,8 +1638,7 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "opensecret" version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7652ddb1661444ea0cbacacbc62c13f5073f1687a2e765e0195ebf29d3e394d" +source = "git+https://github.com/OpenSecretCloud/OpenSecret-SDK?rev=94bfc4efa2cd513b160a0fbefc1acf7af77e49bc#94bfc4efa2cd513b160a0fbefc1acf7af77e49bc" dependencies = [ "aes-gcm", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index b282dcd..6b81429 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,9 +27,15 @@ path = "src/lib.rs" name = "maple-proxy" path = "src/main.rs" +[features] +default = [] +# Explicit development-only opt-in. Release, Docker, and embedded Maple builds +# use default features and cannot accept mock attestation documents. +insecure-local-mock-attestation = ["opensecret/mock-attestation"] + [dependencies] # OpenSecret SDK -opensecret = "3.4.0" +opensecret = { git = "https://github.com/OpenSecretCloud/OpenSecret-SDK", rev = "94bfc4efa2cd513b160a0fbefc1acf7af77e49bc", default-features = false } # Web server axum = { version = "0.8.4", features = ["http2", "macros"] } diff --git a/README.md b/README.md index 3042a1c..c802a48 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ Environment (TEE) processing. ## 🚀 Features - **OpenAI-Compatible Surface** - Models, chat completions, and embeddings endpoints -- **Secure TEE Processing** - All requests processed in secure enclaves +- **Attested TEE Transport** - The OpenSecret SDK establishes an attested, + encrypted channel before inference requests are forwarded - **Lossless Chat Parameters** - Provider-specific request fields pass through unchanged - **Streaming and Non-Streaming** - Supports both chat completion response modes - **Flexible Authentication** - Environment variables or per-request API keys @@ -44,7 +45,7 @@ Set environment variables or use command-line arguments: # Environment Variables export MAPLE_HOST=127.0.0.1 # Server host (default: 127.0.0.1) export MAPLE_PORT=8080 # Server port (default: 8080) -export MAPLE_BACKEND_URL=http://localhost:3000 # Maple backend URL (prod: https://enclave.trymaple.ai) +export MAPLE_BACKEND_URL=https://enclave.trymaple.ai # Maple backend URL export MAPLE_API_KEY=your-maple-api-key # Default API key (optional) export MAPLE_DEBUG=true # Enable debug logging export MAPLE_ENABLE_CORS=true # Enable CORS @@ -57,6 +58,10 @@ Or use CLI arguments: cargo run -- --host 0.0.0.0 --port 8080 --backend-url https://enclave.trymaple.ai ``` +For an unsigned local backend, use `just run-local`. That recipe alone enables +the explicitly named `insecure-local-mock-attestation` Cargo feature. Generic, +release, Docker, and embedded Maple builds leave the feature disabled. + ## 🛠️ Usage ### Using as a Binary @@ -453,9 +458,49 @@ cargo run ``` 1. **Client** makes standard OpenAI API calls to localhost -2. **Maple Proxy** handles authentication and TEE handshake -3. **Requests** are securely forwarded to Maple's TEE infrastructure -4. **Responses** are streamed back to the client in OpenAI format +2. **Maple Proxy** handles authentication and asks the OpenSecret SDK to + establish the TEE channel +3. **OpenSecret SDK** authenticates and authorizes the enclave before accepting + its key and completing key exchange +4. **Requests** are encrypted and forwarded to Maple's TEE infrastructure +5. **Responses** are streamed back to the client in OpenAI format + +### TEE release authorization + +The Sigstore/Rekor release-authorization work belongs in the OpenSecret SDK, +not in Maple Proxy. For each non-local backend, the SDK is expected to: + +1. verify the AWS Nitro attestation document, certificate chain, nonce, and + signature; +2. extract and validate the complete PCR0/PCR1/PCR2 measurement tuple; +3. compare that tuple with the release snapshot embedded in the SDK; and +4. accept the enclave public key and perform key exchange only after the tuple + is present in that snapshot. + +Maple Proxy continues to call `perform_attestation_handshake`; it neither +maintains a second PCR allowlist nor implements a separate Sigstore verifier. +Keeping this policy in the SDK gives every Rust SDK consumer the same +fail-closed authorization boundary before application data is sent. + +There is no Sigstore, Rekor, or other release-metadata network lookup during a +runtime handshake. At SDK update time, the release-snapshot updater verifies +the release manifest and Cosign bundle, including the expected signing identity +and Rekor evidence, before generating the embedded snapshot. Consumers then +review and pin the SDK release containing that generated snapshot. + +Sigstore makes a release statement and its signing identity tamper-evident in +an append-only transparency log. It does **not** prove that an artifact was +reproducibly built, and it does **not** make an old, previously authorized +release fresh. Reproducibility remains a separate Nix rebuild/compare property; +rollback prevention, revocation, or minimum-version policy must also be handled +separately. + +> **Integration status:** this branch pins the exact reviewed SDK integration +> commit with default features disabled. Its embedded release snapshot is +> intentionally empty, so remote handshakes fail closed. Update the pin to a +> reviewed snapshot-bearing commit or published crate after the first signed +> backend release; do not merge or publish this staging state as a working +> production proxy. ## 📝 License diff --git a/justfile b/justfile index 04251b8..b3e8888 100644 --- a/justfile +++ b/justfile @@ -61,7 +61,8 @@ run-with-backend url: # Run pointing to local backend run-local: - @just run-with-backend "http://localhost:3000" + @echo "🚧 Starting with development-only mock attestation enabled" + @bash -c 'set -a; source .env 2>/dev/null; set +a; MAPLE_BACKEND_URL=http://localhost:3000 cargo run --features insecure-local-mock-attestation' # Run pointing to production backend run-prod: From 2f8498fac66746d8ebb8a3e9ead7142a639c904d Mon Sep 17 00:00:00 2001 From: Anthony Ronning <101225832+AnthonyRonning@users.noreply.github.com> Date: Thu, 23 Jul 2026 08:13:27 +0000 Subject: [PATCH 2/3] Advance verified SDK pin --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 91cda4c..3af6005 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1638,7 +1638,7 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "opensecret" version = "3.4.0" -source = "git+https://github.com/OpenSecretCloud/OpenSecret-SDK?rev=94bfc4efa2cd513b160a0fbefc1acf7af77e49bc#94bfc4efa2cd513b160a0fbefc1acf7af77e49bc" +source = "git+https://github.com/OpenSecretCloud/OpenSecret-SDK?rev=61eccfc3eda56e9b492077487c020949bf1a6566#61eccfc3eda56e9b492077487c020949bf1a6566" dependencies = [ "aes-gcm", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 6b81429..91685d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ insecure-local-mock-attestation = ["opensecret/mock-attestation"] [dependencies] # OpenSecret SDK -opensecret = { git = "https://github.com/OpenSecretCloud/OpenSecret-SDK", rev = "94bfc4efa2cd513b160a0fbefc1acf7af77e49bc", default-features = false } +opensecret = { git = "https://github.com/OpenSecretCloud/OpenSecret-SDK", rev = "61eccfc3eda56e9b492077487c020949bf1a6566", default-features = false } # Web server axum = { version = "0.8.4", features = ["http2", "macros"] } From 4df602bca0c99f7a9b8fa2fa2500c95453585ac8 Mon Sep 17 00:00:00 2001 From: Anthony Ronning <101225832+AnthonyRonning@users.noreply.github.com> Date: Thu, 23 Jul 2026 08:15:47 +0000 Subject: [PATCH 3/3] Advance reviewed SDK pin --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3af6005..97ff71c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1638,7 +1638,7 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "opensecret" version = "3.4.0" -source = "git+https://github.com/OpenSecretCloud/OpenSecret-SDK?rev=61eccfc3eda56e9b492077487c020949bf1a6566#61eccfc3eda56e9b492077487c020949bf1a6566" +source = "git+https://github.com/OpenSecretCloud/OpenSecret-SDK?rev=1bd7196043b26b3a2f8080534bd14031afcd5cc8#1bd7196043b26b3a2f8080534bd14031afcd5cc8" dependencies = [ "aes-gcm", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 91685d0..008d40a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ insecure-local-mock-attestation = ["opensecret/mock-attestation"] [dependencies] # OpenSecret SDK -opensecret = { git = "https://github.com/OpenSecretCloud/OpenSecret-SDK", rev = "61eccfc3eda56e9b492077487c020949bf1a6566", default-features = false } +opensecret = { git = "https://github.com/OpenSecretCloud/OpenSecret-SDK", rev = "1bd7196043b26b3a2f8080534bd14031afcd5cc8", default-features = false } # Web server axum = { version = "0.8.4", features = ["http2", "macros"] }