Files
OpenShell/docs/sandboxes/inference-routing.mdx
John T. Myers f4dc6be4b2 refactor(inference): remove managed inference routes (#3195)
* refactor(inference): remove managed inference routes

Closes #3172

Remove the inference route control plane, inference.local data path, built-in router crate, and SDK surface. Move inference workloads to explicitly imported provider profiles and native endpoints, with migration cleanup and updated tests and documentation.

Signed-off-by: John Myers <9696606+johntmyers@users.noreply.github.com>

* fix(policy): preserve alternate upstream isolation

Restore the provider policy activation guard so legacy OpenAI and Anthropic providers configured for alternate base URLs do not grant egress to the built-in public vendor endpoints.

Signed-off-by: John Myers <9696606+johntmyers@users.noreply.github.com>

---------

Signed-off-by: John Myers <9696606+johntmyers@users.noreply.github.com>
2026-09-09 18:47:22 +00:00

312 lines
11 KiB
Plaintext

---
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
title: "Provider-backed Inference"
sidebar-title: "Provider-backed Inference"
description: "Grant a sandbox access to model providers through provider profiles, attachments, and native endpoints."
keywords: "Generative AI, Cybersecurity, Inference, Provider Profiles, Credentials, LLM"
position: 8
---
OpenShell grants model-provider access through provider profiles and sandbox
attachments. The workload calls the provider's native API. OpenShell evaluates
the request against the profile-derived network policy and substitutes the real
credential only at an endpoint authorized by that profile.
This keeps the complete access contract in one place:
| Concern | Owner |
|---|---|
| Credential and refresh lifecycle | Provider instance |
| Authorized hosts, ports, paths, and binaries | Provider profile |
| Which workload receives access | Sandbox provider attachment |
| Base URL, model, request shape, and timeout | Native client or workload configuration |
## Define and Attach a Hosted Provider
Start from an existing profile, review its access, and import it under a new
ID. For example, export the NVIDIA profile:
```shell
openshell provider profile export nvidia -o yaml > nvidia-native.yaml
```
In `nvidia-native.yaml`, change `id` to `nvidia-native`, give the profile a
distinct `display_name`, and set `binaries` to the paths that may call the API.
Keep the credential and endpoint definitions you intend to grant. For a Python
workload, the edited fields can look like:
```yaml
id: nvidia-native
display_name: NVIDIA Native API
binaries:
- /usr/bin/python3
- /usr/bin/python3.13
- /usr/local/bin/python
- /sandbox/.venv/**
```
Lint and import the complete edited profile, then create a provider from its
new ID:
```shell
openshell provider profile lint -f nvidia-native.yaml
openshell provider profile import -f nvidia-native.yaml
openshell provider create \
--name nvidia-prod \
--type nvidia-native \
--from-existing
openshell sandbox create \
--name inference-demo \
--provider nvidia-prod \
-- python app.py
```
The imported provider profile supplies `NVIDIA_API_KEY` as an opaque placeholder and
allows the profile's native endpoint. Configure the client with the real model
identifier:
```python
import os
from openai import OpenAI
client = OpenAI(
base_url="https://integrate.api.nvidia.com/v1",
api_key=os.environ["NVIDIA_API_KEY"],
timeout=300,
)
response = client.responses.create(
model="nvidia/nemotron-3-nano-30b-a3b",
input="Hello!",
)
print(response.output_text)
```
Use the same export, edit, and import flow for OpenAI, Anthropic, or another
hosted service. Set a new profile ID, retain only the endpoints and credentials
the workload needs, and name the actual client binaries. Provider attachment
does not select or rewrite a model.
This release still loads built-in profiles for compatibility, so existing
providers continue to resolve their profiles. Treat those built-ins as starting
templates for new provider definitions rather than the primary setup workflow.
## Attach a Provider to a Running Sandbox
```shell
openshell sandbox provider attach inference-demo nvidia-prod
openshell sandbox provider list inference-demo
```
Running sandboxes poll for provider and effective-policy changes. Launch a new
process after attachment so it receives the new credential placeholder:
```shell
openshell sandbox exec inference-demo -- python app.py
```
An already-running process does not gain new environment variables. Credential
rotation and detach still take effect immediately at placeholder resolution.
Detach the provider to revoke its policy and credential access:
```shell
openshell sandbox provider detach inference-demo nvidia-prod
```
## Use a Custom or Self-hosted Endpoint
Do not reuse the built-in `openai` or `anthropic` profile for an alternate
host. Those profiles bind credentials to the public vendor endpoints. Import a
profile that names the intended endpoint and the binaries that may call it.
For a credentialless Ollama server on the gateway host, save this profile as
`ollama-openai.yaml`:
```yaml
id: ollama-openai
display_name: Ollama
description: Host-local Ollama OpenAI-compatible API
category: inference
inference_capable: true
credentials: []
endpoints:
- host: host.openshell.internal
port: 11434
protocol: rest
access: read-write
enforcement: enforce
binaries:
- /usr/bin/curl
- /usr/local/bin/curl
- /usr/bin/python3
- /usr/local/bin/python
- /sandbox/.uv/python/**
- /sandbox/.venv/**
```
Import the profile, create an instance, and attach it:
```shell
openshell provider profile lint -f ollama-openai.yaml
openshell provider profile import -f ollama-openai.yaml
openshell provider create --name ollama --type ollama-openai
openshell sandbox create \
--name ollama-client \
--provider ollama \
--env OPENAI_BASE_URL=http://host.openshell.internal:11434/v1 \
-- python app.py
```
Use any non-empty placeholder value if the client library requires an API key
for a server that does not authenticate requests:
```python
import os
from openai import OpenAI
client = OpenAI(
base_url=os.environ["OPENAI_BASE_URL"],
api_key="unused",
)
response = client.chat.completions.create(
model="qwen3.5:0.8b",
messages=[{"role": "user", "content": "Hello"}],
)
```
For an authenticated alternate endpoint, declare a credential in the custom
profile, bind it to that endpoint, and create the provider from the original
credential source. OpenShell never exports stored credential values.
## Verify Access
Inspect the effective policy, including provider-derived entries:
```shell
openshell policy get inference-demo --full
```
Then run a native request from a new sandbox process. A successful request
confirms endpoint policy, binary attribution, credential substitution, DNS,
and upstream service behavior.
If the request is denied:
- Confirm the provider is attached with `openshell sandbox provider list`.
- Confirm the caller binary and native endpoint appear in
`openshell policy get <sandbox> --full`.
- If the provider was attached after the process started, launch a new process.
- If the sandbox uses a gateway global policy override, add the native endpoint
there because a global override suppresses provider-derived policy layers.
- Inspect logs for `credential_endpoint_mismatch`. That error means policy
admitted the request but the provider profile did not authorize its
credential at the requested endpoint.
## Migrate from Managed Inference Routes
OpenShell removed the workspace-global managed inference route and the
`openshell inference` commands. Upgrades remove stored route records. Provider
records, provider refresh configuration, and existing sandbox attachments are
preserved. Built-in profiles remain available during the transition, but new
setups should import an explicit profile under a new ID.
The old route cannot be converted automatically. It applied one provider and
model to every sandbox in a workspace, while provider attachments intentionally
grant access to selected sandboxes. OpenShell cannot infer which sandboxes
should receive that authority.
### Now
Earlier releases configured one shared route:
```shell
openshell provider create --name nvidia-prod --type nvidia --from-existing
openshell inference set \
--provider nvidia-prod \
--model nvidia/nemotron-3-nano-30b-a3b \
--timeout 300
```
Clients called `https://inference.local`, supplied a placeholder key and model,
and relied on OpenShell to rewrite the request.
### After
Export the old provider type's profile, edit its ID and access contract, import
it, and create a replacement provider from the original credential source:
```shell
openshell provider profile export nvidia -o yaml > nvidia-native.yaml
# Edit id, display_name, endpoints, and binaries in nvidia-native.yaml.
openshell provider profile lint -f nvidia-native.yaml
openshell provider profile import -f nvidia-native.yaml
openshell provider create \
--name nvidia-native-prod \
--type nvidia-native \
--from-existing
openshell sandbox provider attach inference-demo nvidia-native-prod
```
OpenShell does not export stored credential values or change a provider's
profile type in place. If the original credential source is unavailable, the
compatibility built-in lets you attach the preserved provider while you arrange
credential rotation into the replacement provider.
Update each workload to:
1. Call the provider's native endpoint.
2. Read the credential variable declared by its profile.
3. Send the real provider model identifier.
4. Configure request timeouts in the client.
5. Use the provider's native request format.
Launch a new process after attachment and verify a native request before
upgrading production workloads. Code that still calls `inference.local` fails
DNS resolution because OpenShell no longer resolves or trusts that virtual
host.
### Migration Checklist
Before upgrading, record the old provider, model, and timeout with the previous
release's `openshell inference get`. Identify actual consumers, export and edit
the source profile, import it under a new ID, and create the replacement
provider from the original credential source. Attach it only to those
sandboxes, migrate their clients, and test the native path while the old route
is still available. Delete the old route on the previous release to expose
missed consumers. After upgrading the gateway, delete and recreate every
pre-upgrade sandbox so no old supervisor, DNS entry, trust material, or cached
route survives. Reapply only the provider attachments each replacement
sandbox needs.
Special cases require additional work:
- A provider with an alternate `OPENAI_BASE_URL` or `ANTHROPIC_BASE_URL` needs
an endpoint-bearing custom profile for that host.
- Host-local services need `host.openshell.internal` or a reachable LAN/service
hostname, not `127.0.0.1` or `localhost`.
- Google Vertex AI clients must use the native Vertex endpoint and
authentication behavior. See [Google Vertex AI](/providers/google-vertex-ai).
- A bridge-fronted AWS Bedrock deployment needs a custom profile that declares
the bridge endpoint and allowed client binaries.
## Security Differences
Provider attachment preserves credential non-disclosure: workloads receive
opaque placeholders, and the proxy substitutes a real credential only after
network policy and endpoint binding both pass. Native requests are no longer
filtered or rewritten by a model-specific router. The provider profile's L7
rules therefore define the allowed API surface, and the workload controls
headers, model selection, request shape, streaming, and timeout behavior.
## Next Steps
- [Profiles](/providers/profiles)
- [Providers](/sandboxes/manage-providers)
- [Customize Sandbox Policies](/sandboxes/policies)
- [Google Vertex AI](/providers/google-vertex-ai)