Files
OpenShell/tasks/rust.toml
Piotr Mlocek bdabb54cb3 fix(security): authenticate extension services (#2638)
* fix(security): authenticate extension services

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>

* feat(extension-core): verify gateway JWTs

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>

* refactor(extension-core): keep inbound verification external

This should become an extension SDK package.

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>

* fix(security): harden the extension authentication contract

Follow-up hardening on the alpha extension authentication mechanism.

Claim contract:
- Extension tokens carry an explicit `typ` of `openshell-ext+jwt`. They
  share a signing key with sandbox-to-gateway admission tokens and were
  otherwise separated by audience alone, so a verifier that neglects to
  check `aud` could accept a gateway credential. The header is a second,
  independent discriminator.
- Publish OIDC-shaped discovery at `/.well-known/openid-configuration`
  so a service configured with only the gateway URL can learn the exact
  expected issuer and the JWKS location. It is shaped, not compliant:
  `issuer` is the gateway identity, not the serving URL.

Audience agreement:
- `MiddlewareManifest` and `InterceptorManifest` gain `expected_audience`.
  The audience is otherwise configured independently on each side of the
  boundary, where a mismatch surfaces only as an opaque authentication
  failure on every call. OpenShell now compares the two and fails at
  startup. An empty field keeps the check off for existing services.

Compatibility:
- Add `allow_insecure_transport` per registration. Enabling gateway JWT
  signing previously made any plaintext endpoint a hard startup failure,
  including the endpoint form used in our own documentation. The opt-out
  attaches no credential, is refused by the gateway if a supervisor asks
  for one, and warns at every startup.
- Make the transport requirement kind-aware. A middleware endpoint must
  be reachable from every sandbox supervisor, so only interceptors may
  use a gateway-local Unix socket.

Credential lifecycle:
- Replace the process-global slot map with a supervisor-owned
  `ExtensionCredentialStore` shared explicitly across the gateway
  connections the supervisor opens, removing test-order coupling.
- Rotate only when a credential is missing or has passed four fifths of
  its lifetime. Configuration polling ran every ten seconds against
  fifteen-minute credentials, so each poll re-ran gateway effective-policy
  resolution and re-minted the gateway token.
- Bound credential minting per sandbox, since each request resolves the
  caller's effective policy.

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>

* docs: record alpha extension authentication in RFC appendices

Restore the RFC 0009 and 0010 bodies to their accepted text and move
every extension-authentication update into appendices instead. An RFC
records a decision at a point in time; superseding detail belongs
alongside it rather than rewritten into it.

RFC 0009's appendix carries the shared contract: claims, authorization,
key distribution, the `allow_insecure_transport` replacement for the
body's `allow_insecure`, and residual risks. RFC 0010's records only
what differs for interceptors and links to it. The existing
protocol-extensions appendix, which parked the phase 2 transport
question, now points forward to what was built.

Also document the audience handshake, the discovery endpoint, the
`typ` requirement, and `jti` replay guidance in the extensibility and
gateway configuration pages, and correct the middleware transport
guidance: middleware endpoints must be reachable from sandbox
supervisors, so Unix sockets are not an option there.

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>

* refactor(extension-core): abstract extension server trust

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>

* docs(core): update middleware manifest example

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>

* fix(extension-auth): preserve unsigned gateway compatibility

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>

* fix(extension-auth): reject cross-domain token replay

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>

---------

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
2026-08-14 20:34:10 +00:00

74 lines
3.4 KiB
TOML

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
# Rust check, lint, and format tasks
["rust:check"]
description = "Check all Rust crates for errors"
run = "cargo check --workspace"
run_windows = "powershell -NoProfile -ExecutionPolicy Bypass -File tasks/scripts/windows-msvc.ps1 check native"
hide = true
["rust:lint"]
description = "Lint Rust code with Clippy (deny warnings)"
run = [
"cargo clippy --workspace --all-targets -- -D warnings",
"cargo clippy --manifest-path e2e/rust/Cargo.toml --all-targets -- -D warnings",
"cargo check --manifest-path examples/governance-interceptor/Cargo.toml --all-targets",
]
run_windows = "powershell -NoProfile -ExecutionPolicy Bypass -File tasks/scripts/windows-msvc.ps1 lint native"
hide = true
["rust:format"]
description = "Format Rust code"
run = [
"cargo fmt --all",
"cargo fmt --manifest-path e2e/rust/Cargo.toml --all",
"cargo fmt --manifest-path examples/governance-interceptor/Cargo.toml --all",
]
hide = true
["rust:format:check"]
description = "Check Rust formatting"
run = [
"cargo fmt --all -- --check",
"cargo fmt --manifest-path e2e/rust/Cargo.toml --all -- --check",
"cargo fmt --manifest-path examples/governance-interceptor/Cargo.toml --all -- --check",
]
hide = true
["rust:deny"]
description = "Check dependencies for all cargo-deny rules"
run = "cargo deny check"
["rust:deny:policy"]
description = "Check dependencies for license violations, bans, and source restrictions"
run = "cargo deny check licenses bans sources"
["rust:verify:telemetry-off"]
description = "Verify telemetry emission code is compiled out with --no-default-features"
run = [
# Positive control: the default (telemetry-on) gateway must contain the
# markers, so the absent checks below can never become silently vacuous.
"cargo build -p openshell-server --bin openshell-gateway",
"tasks/scripts/verify-telemetry-compiled-out.sh present target/debug/openshell-gateway",
# Guard: telemetry-free builds must contain no telemetry markers.
"cargo build -p openshell-server --bin openshell-gateway --no-default-features",
"tasks/scripts/verify-telemetry-compiled-out.sh absent target/debug/openshell-gateway",
"cargo build -p openshell-sandbox --bin openshell-sandbox --no-default-features --features bundled-ca-roots",
"tasks/scripts/verify-telemetry-compiled-out.sh absent target/debug/openshell-sandbox",
]
["rust:verify:system-ca-roots"]
description = "Verify system CA roots build mode compiles and excludes bundled Mozilla root crates"
run = [
# Check that the sandbox compiles cleanly in system CA roots mode (all
# defaults except bundled-ca-roots).
"cargo check -p openshell-sandbox --all-targets --no-default-features --features system-ca-roots",
# Guard: webpki-roots must not appear in the dependency graph.
"bash -c 'if cargo tree -p openshell-sandbox -i webpki-roots --no-default-features --features system-ca-roots 2>/dev/null | grep -q webpki-roots; then echo \"ERROR: webpki-roots found in system CA roots build\" >&2; exit 1; fi'",
# Guard: webpki-root-certs must not appear either (webpki-roots re-exports it).
"bash -c 'if cargo tree -p openshell-sandbox -i webpki-root-certs --no-default-features --features system-ca-roots 2>/dev/null | grep -q webpki-root-certs; then echo \"ERROR: webpki-root-certs found in system CA roots build\" >&2; exit 1; fi'",
]