mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-30 07:33:59 +08:00
docs(sdk): clarify extension and E2E setup
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
This commit is contained in:
@@ -87,10 +87,6 @@ rotates their in-memory slots without rebuilding clients, and publishes the
|
||||
public verification key at `/.well-known/jwks.json` alongside OIDC-shaped
|
||||
discovery metadata at `/.well-known/openid-configuration`. HTTPS extensions can
|
||||
pin an operator-provided CA while retaining endpoint-hostname verification.
|
||||
Rust extension services use the opt-in `openshell-sdk::extension` surface to
|
||||
verify these credentials from operator-provisioned Ed25519 public keys or JWKS
|
||||
documents and normalize gateway and supervisor caller identities. Key refresh
|
||||
remains a service deployment concern.
|
||||
|
||||
Extension credentials reuse the sandbox signing key and are separated from
|
||||
sandbox-to-gateway admission tokens by exact audience and by an explicit
|
||||
|
||||
@@ -49,19 +49,16 @@ mTLS (client certificates) is not supported.
|
||||
SDK-shaped enums rather than raw proto integers. Failures map to a typed
|
||||
`SdkError` with a discriminable kind.
|
||||
|
||||
Enable the `extension` Cargo feature when implementing an operator-run
|
||||
OpenShell extension service:
|
||||
Enable the `extension` Cargo feature when building an OpenShell extension
|
||||
service:
|
||||
|
||||
```toml
|
||||
openshell-sdk = { version = "...", features = ["extension"] }
|
||||
```
|
||||
|
||||
The `extension` module verifies gateway-minted EdDSA extension JWTs from a
|
||||
trusted public key or JWKS document. `GatewayJwtAuthenticator` pins the token
|
||||
type, algorithm, issuer, audience, lifetime, and caller identity shape, then
|
||||
returns an `AuthenticatedCaller` that service handlers can authorize by caller
|
||||
kind. This feature is opt-in so gateway-only SDK consumers do not compile the
|
||||
extension verification dependencies.
|
||||
The `extension` module provides common SDK building blocks for extension
|
||||
services. It currently handles caller verification; shared service interfaces
|
||||
and observability support will follow.
|
||||
|
||||
## Modules
|
||||
|
||||
@@ -74,7 +71,7 @@ extension verification dependencies.
|
||||
| `oidc` | OIDC token handling at the transport layer. |
|
||||
| `refresh` | `Refresh` trait and single-flight refresh coalescing. |
|
||||
| `edge_tunnel` | Cloudflare Access tunnel dialer. |
|
||||
| `extension` | Opt-in service-side authentication and identity types for operator-run extensions. |
|
||||
| `extension` | Opt-in SDK building blocks for extension services. |
|
||||
| `error` | `SdkError` taxonomy. |
|
||||
| `types` | Curated request/response types and proto conversions. |
|
||||
| `raw` | Escape hatch re-exporting the generated tonic clients. |
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//! APIs for implementing operator-run `OpenShell` extension services.
|
||||
//! APIs for building `OpenShell` extension services.
|
||||
//!
|
||||
//! Enable the `extension` Cargo feature to verify gateway-minted extension
|
||||
//! credentials and authorize callers without depending on gateway internals.
|
||||
//! This feature is the home for shared extension interfaces, verification, and
|
||||
//! observability. It currently provides gateway-minted credential verification.
|
||||
|
||||
mod verification;
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ Return your expected audience in the `expected_audience` field of your `Describe
|
||||
|
||||
Provision the trusted gateway URL, expected gateway ID, and public key or JWKS through the deployment. This operator-provisioned key material is the authoritative cold-start trust anchor. The expected issuer is exactly `openshell-gateway:<gateway_id>`; fetching JWKS does not establish that identity by itself. After initial trust is established, `GET /.well-known/openid-configuration` and its `jwks_uri` provide steady-state key refresh and operational convenience. The document is OIDC-shaped rather than OIDC-compliant: `issuer` is the gateway identity, not the URL serving the document, so compare `iss` against the configured value and fetch updates only over authenticated TLS at the trusted gateway URL.
|
||||
|
||||
Rust services can enable the `extension` Cargo feature on `openshell-sdk` and use `openshell_sdk::extension::GatewayJwtAuthenticator`. Construct it from a trusted Ed25519 public key and `kid`, or from a trusted JWKS document, then call `authenticate_request` on each tonic request. The returned `AuthenticatedCaller` exposes the normalized caller kind, subject, and optional sandbox ID for RPC-specific authorization. Key refresh remains deployment-owned; rebuild the authenticator after accepting a refreshed key set from the trusted gateway URL.
|
||||
Rust services can enable the `extension` Cargo feature on `openshell-sdk` for common extension interfaces, verification, and observability. Caller verification is available today through `openshell_sdk::extension::GatewayJwtAuthenticator`; additional SDK support will follow.
|
||||
|
||||
Cache keys by `kid`. Validate, at minimum:
|
||||
|
||||
|
||||
@@ -279,6 +279,9 @@ connect_current_container_to_docker_network() {
|
||||
GATEWAY_HOST_ALIAS_IP="${container_ip}"
|
||||
}
|
||||
|
||||
# Build and launch an authenticated TLS extension service that is reachable
|
||||
# from the host gateway and sandbox containers. The focused middleware E2E lane
|
||||
# opts into this fixture; other Docker E2E callers retain the existing setup.
|
||||
start_middleware_fixture() {
|
||||
local manifest="${ROOT}/e2e/supervisor-middleware-fixture/Cargo.toml"
|
||||
local binary="${TARGET_DIR}/debug/openshell-e2e-middleware-fixture"
|
||||
@@ -290,8 +293,12 @@ start_middleware_fixture() {
|
||||
CARGO_TARGET_DIR="${TARGET_DIR}" cargo build --locked --manifest-path "${manifest}"
|
||||
|
||||
if [ -n "${GATEWAY_HOST_ALIAS_IP}" ]; then
|
||||
# In GitHub Actions, the fixture and gateway run in the job container. The
|
||||
# wrapper has already attached that container to the sandbox network.
|
||||
fixture_host="${GATEWAY_HOST_ALIAS_IP}"
|
||||
elif [ "$(uname -s)" = "Linux" ]; then
|
||||
# In a native Linux run, the fixture and gateway run on the host. The
|
||||
# bridge gateway address is reachable from both the host and containers.
|
||||
fixture_host="$(docker network inspect \
|
||||
--format '{{(index .IPAM.Config 0).Gateway}}' \
|
||||
"${DOCKER_NETWORK_NAME}")"
|
||||
@@ -306,6 +313,8 @@ start_middleware_fixture() {
|
||||
fi
|
||||
|
||||
mkdir -p "${fixture_dir}"
|
||||
# Generate a one-run CA and a CA-signed server certificate whose IP SAN
|
||||
# matches the shared address used by the gateway and sandbox supervisor.
|
||||
openssl req -x509 -newkey rsa:2048 -nodes \
|
||||
-keyout "${fixture_dir}/ca.key" \
|
||||
-out "${fixture_dir}/ca.crt" \
|
||||
@@ -335,6 +344,8 @@ start_middleware_fixture() {
|
||||
|
||||
fixture_port="$(e2e_pick_port)"
|
||||
echo "Starting supervisor middleware E2E fixture on ${fixture_host}:${fixture_port}..."
|
||||
# Give the fixture both sides of the trust relationship: its TLS identity and
|
||||
# the gateway identity/audience required to verify extension bearer tokens.
|
||||
OPENSHELL_E2E_MIDDLEWARE_LISTEN="0.0.0.0:${fixture_port}" \
|
||||
OPENSHELL_E2E_MIDDLEWARE_TLS_CERT="${fixture_dir}/tls.crt" \
|
||||
OPENSHELL_E2E_MIDDLEWARE_TLS_KEY="${fixture_dir}/tls.key" \
|
||||
@@ -345,6 +356,8 @@ start_middleware_fixture() {
|
||||
"${binary}" >"${MIDDLEWARE_FIXTURE_LOG}" 2>&1 &
|
||||
MIDDLEWARE_FIXTURE_PID=$!
|
||||
|
||||
# A TCP readiness probe is sufficient here: the gateway performs the
|
||||
# authenticated gRPC Describe call when it starts immediately afterward.
|
||||
local attempt
|
||||
for attempt in $(seq 1 100); do
|
||||
if ! kill -0 "${MIDDLEWARE_FIXTURE_PID}" 2>/dev/null; then
|
||||
@@ -587,6 +600,8 @@ echo "Starting openshell-gateway on port ${HOST_PORT} (namespace: ${E2E_NAMESPAC
|
||||
echo "Using sandbox image: ${SANDBOX_IMAGE} (pull policy: ${SANDBOX_IMAGE_PULL_POLICY})"
|
||||
e2e_generate_gateway_jwt "${JWT_DIR}"
|
||||
if [ "${OPENSHELL_E2E_MIDDLEWARE_FIXTURE:-0}" = "1" ]; then
|
||||
# The gateway validates middleware with Describe during startup, so the
|
||||
# extension service and its trust material must exist first.
|
||||
start_middleware_fixture
|
||||
fi
|
||||
|
||||
@@ -615,6 +630,8 @@ GATEWAY_CONFIG="${STATE_DIR}/gateway.toml"
|
||||
fi
|
||||
fi
|
||||
if [ -n "${MIDDLEWARE_FIXTURE_ENDPOINT}" ]; then
|
||||
# Register only the opt-in fixture, pinning its ephemeral CA and the exact
|
||||
# audience that both the gateway token issuer and fixture verifier expect.
|
||||
printf '[[openshell.supervisor.middleware]]\n'
|
||||
printf 'name = "e2e-scripted"\n'
|
||||
printf 'grpc_endpoint = %s\n' "$(toml_string "${MIDDLEWARE_FIXTURE_ENDPOINT}")"
|
||||
|
||||
Reference in New Issue
Block a user