Files
OpenShell/docs/sandboxes/policies.md
Miyoung ChoiandKirit93 c420109a6a docs: add dedicated gateway docs, network policy tutorial, and license page (#294)
* Added gateway and tutorial

* add new content and polish, add license terms

* small fix

* tiny fix

* polish bit more

* change warning to important

* fix support matrix

* small fix

* add a note about example script

* fix link

* fix link

* improve

* fix links

* unclutter sandbax index more

* improve titles

* tiny style fix

* style guide on inferences, release notes link to gh

* polish

* nit

* switch version to 0.0.3

* incorporate feedback

---------

Co-authored-by: Kirit93 <kthadaka@nvidia.com>
2026-03-14 09:53:01 -07:00

9.8 KiB

title, description, topics, tags, content
title description topics tags content
page nav
Customize Sandbox Policies Policies
Apply, iterate, and debug sandbox network policies with hot-reload on running OpenShell sandboxes.
Generative AI
Cybersecurity
Policy
Network Policy
Sandbox
Security
Hot Reload
type difficulty audience
how_to technical_intermediate
engineer

Customize Sandbox Policies

Use this page to apply and iterate policy changes on running sandboxes. For a full field-by-field YAML definition, use the Policy Schema Reference.

Policy Structure

A policy has static sections filesystem_policy, landlock, and process that are locked at sandbox creation, and dynamic sections network_policies and inference that are hot-reloadable on a running sandbox.

version: 1

# Static: locked at sandbox creation. Paths the agent can read vs read/write.
filesystem_policy:
  read_only: [/usr, /lib, /etc]
  read_write: [/sandbox, /tmp]

# Static: Landlock LSM kernel enforcement. best_effort uses highest ABI the host supports.
landlock:
  compatibility: best_effort

# Static: Unprivileged user/group the agent process runs as.
process:
  run_as_user: sandbox
  run_as_group: sandbox

# Dynamic: hot-reloadable. Named blocks of endpoints + binaries allowed to reach them.
network_policies:
  my_api:
    name: my-api
    endpoints:
      - host: api.example.com
        port: 443
        protocol: rest
        tls: terminate
        enforcement: enforce
        access: full
    binaries:
      - path: /usr/bin/curl

# Dynamic: hot-reloadable. Routing hints this sandbox can use for inference (e.g. local, nvidia).
inference:
  allowed_routes: [local]

Static sections are locked at sandbox creation. Changing them requires destroying and recreating the sandbox. Dynamic sections can be updated on a running sandbox with openshell policy set and take effect without restarting.

Section Type Description
filesystem_policy Static Controls which directories the agent can access on disk. Paths are split into read_only and read_write lists. Any path not listed in either list is inaccessible. Set include_workdir: true to automatically add the agent's working directory to read_write. Landlock LSM enforces these restrictions at the kernel level.
landlock Static Configures Landlock LSM enforcement behavior. Set compatibility to best_effort (use the highest ABI the host kernel supports) or hard_requirement (fail if the required ABI is unavailable).
process Static Sets the OS-level identity for the agent process. run_as_user and run_as_group default to sandbox. Root (root or 0) is rejected. The agent also runs with seccomp filters that block dangerous system calls.
network_policies Dynamic Controls network access for the sandbox. Each block has a name, a list of endpoints (host, port, protocol, and optional rules), and a list of binaries allowed to use those endpoints.
Every outbound connection goes through the proxy, which queries the {doc}policy engine <../about/architecture> with the destination and calling binary. A connection is allowed only when both match an entry in the same policy block.
For endpoints with protocol: rest and tls: terminate, each HTTP request is also checked against that endpoint's rules (method and path).
Endpoints without protocol or tls allow the TCP stream through without inspecting payloads.
If no endpoint matches and inference routes are configured, the request may be rerouted for inference. Otherwise the connection is denied.
inference Dynamic Controls which inference routing backends the sandbox can use. Set allowed_routes to a list of route names (for example, [local] or [local, nvidia]). When an outbound request does not match any network_policies entry, the proxy checks whether the destination matches a configured inference route. If it does and the route is in allowed_routes, the request is forwarded to that backend.

Apply a Custom Policy

Pass a policy YAML file when creating the sandbox:

$ openshell sandbox create --policy ./my-policy.yaml -- claude

openshell sandbox create keeps the sandbox running after the initial command exits, which is useful when you plan to iterate on the policy. Add --no-keep if you want the sandbox deleted automatically instead.

To avoid passing --policy every time, set a default policy with an environment variable:

$ export OPENSHELL_SANDBOX_POLICY=./my-policy.yaml
$ openshell sandbox create -- claude

The CLI uses the policy from OPENSHELL_SANDBOX_POLICY whenever --policy is not explicitly provided.

Iterate on a Running Sandbox

To change what the sandbox can access, pull the current policy, edit the YAML, and push the update. The workflow is iterative: create the sandbox, monitor logs for denied actions, pull the policy, modify it, push, and verify.

flowchart TD
    A["1. Create sandbox with initial policy"] --> B["2. Monitor logs for denied actions"]
    B --> C["3. Pull current policy"]
    C --> D["4. Modify the policy YAML"]
    D --> E["5. Push updated policy"]
    E --> F["6. Verify the new revision loaded"]
    F --> B

    style A fill:#76b900,stroke:#000000,color:#000000
    style B fill:#76b900,stroke:#000000,color:#000000
    style C fill:#76b900,stroke:#000000,color:#000000
    style D fill:#ffffff,stroke:#000000,color:#000000
    style E fill:#76b900,stroke:#000000,color:#000000
    style F fill:#76b900,stroke:#000000,color:#000000

    linkStyle default stroke:#76b900,stroke-width:2px

The following steps outline the hot-reload policy update workflow.

  1. Create the sandbox with your initial policy by following Apply a Custom Policy above (or set OPENSHELL_SANDBOX_POLICY).

  2. Monitor denials. Each log entry shows host, port, binary, and reason. Alternatively, use openshell term for a live dashboard.

    $ openshell logs <name> --tail --source sandbox
    
  3. Pull the current policy. Strip the metadata header (Version, Hash, Status) before reusing the file.

    $ openshell policy get <name> --full > current-policy.yaml
    
  4. Edit the YAML: add or adjust network_policies entries, binaries, access or rules, or inference.allowed_routes.

  5. Push the updated policy. Exit codes: 0 = loaded, 1 = validation failed, 124 = timeout.

    $ openshell policy set <name> --policy current-policy.yaml --wait
    
  6. Verify the new revision. If status is loaded, repeat from step 2 as needed; if failed, fix the policy and repeat from step 4.

    $ openshell policy list <name>
    

Debug Denied Requests

Check openshell logs <name> --tail --source sandbox for the denied host, path, and binary.

When triaging denied requests, check:

  • Destination host and port to confirm which endpoint is missing.
  • Calling binary path to confirm which binaries entry needs to be added or adjusted.
  • HTTP method and path (for REST endpoints) to confirm which rules entry needs to be added or adjusted.

Then push the updated policy as described above.

Examples

Add these blocks to the network_policies section of your sandbox policy. Apply with openshell policy set <name> --policy <file> --wait. Use Simple endpoint for host-level allowlists and Granular rules for method/path control.

:::::{tab-set}

::::{tab-item} Simple endpoint Allow pip install and uv pip install to reach PyPI:

  pypi:
    name: pypi
    endpoints:
      - host: pypi.org
        port: 443
      - host: files.pythonhosted.org
        port: 443
    binaries:
      - { path: /usr/bin/pip }
      - { path: /usr/local/bin/uv }

Endpoints without protocol or tls use TCP passthrough — the proxy allows the stream without inspecting payloads. ::::

::::{tab-item} Granular rules Allow Claude and the GitHub CLI to reach api.github.com with per-path rules: read-only (GET, HEAD, OPTIONS) and GraphQL (POST) for all paths; full write access for alpha-repo; and create/edit issues only for bravo-repo. Replace <org_name> with your GitHub org or username.

:::{tip} For an end-to-end walkthrough that combines this policy with a GitHub credential provider and sandbox creation, refer to {doc}/tutorials/github-sandbox. :::

  github_repos:
    name: github_repos
    endpoints:
      - host: api.github.com
        port: 443
        protocol: rest
        tls: terminate
        enforcement: enforce
        rules:
          - allow:
              method: GET
              path: "/**"
          - allow:
              method: HEAD
              path: "/**"
          - allow:
              method: OPTIONS
              path: "/**"
          - allow:
              method: POST
              path: "/graphql"
          - allow:
              method: "*"
              path: "/repos/<org_name>/alpha-repo/**"
          - allow:
              method: POST
              path: "/repos/<org_name>/bravo-repo/issues"
          - allow:
              method: PATCH
              path: "/repos/<org_name>/bravo-repo/issues/*"
    binaries:
      - { path: /usr/local/bin/claude }
      - { path: /usr/bin/gh }

Endpoints with protocol: rest and tls: terminate enable HTTP request inspection — the proxy decrypts TLS and checks each HTTP request against the rules list. ::::

:::::

Next Steps

Explore related topics:

  • To learn about network access rules and sandbox isolation layers, refer to {doc}index.
  • To view the full field-by-field YAML definition, refer to the Policy Schema Reference.
  • To review the default policy breakdown, refer to {doc}../reference/default-policy.