mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-15 05:09:44 +08:00
* feat(sandbox): honor Docker OCI working directories Signed-off-by: Matthew Grossman <mgrossman@nvidia.com> * fix(sandbox): honor effective workspace access Signed-off-by: Matthew Grossman <mgrossman@nvidia.com> * test(sandbox): cover enforced workspace denial Signed-off-by: Matthew Grossman <mgrossman@nvidia.com> * docs(docker): explain effective workdir checks Signed-off-by: Matthew Grossman <mgrossman@nvidia.com> * fix(sandbox): validate effective workspace writes Signed-off-by: Matthew Grossman <mgrossman@nvidia.com> * fix(sandbox): reserve supervisor control roots Signed-off-by: Matthew Grossman <mgrossman@nvidia.com> * refactor(sandbox): centralize control paths Signed-off-by: Matthew Grossman <mgrossman@nvidia.com> * fix(sandbox): reserve OCI runtime mount roots Signed-off-by: Matthew Grossman <mgrossman@nvidia.com> --------- Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
219 lines
8.2 KiB
Plaintext
219 lines
8.2 KiB
Plaintext
---
|
|
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
title: "Write Your First Sandbox Network Policy"
|
|
sidebar-title: "First Network Policy"
|
|
slug: "get-started/tutorials/first-network-policy"
|
|
description: "Learn how OpenShell network policies work by creating a sandbox, observing default-deny in action, and applying a fine-grained L7 read-only rule."
|
|
keywords: "Generative AI, Cybersecurity, Tutorial, Policy, Network Policy, Sandbox, Security"
|
|
---
|
|
|
|
This tutorial shows how OpenShell's network policy system works in under five minutes. You create a sandbox, watch a request get blocked by the default-deny policy, apply a fine-grained L7 rule, and verify that reads are allowed while writes are blocked, all without restarting anything.
|
|
|
|
After completing this tutorial, you understand:
|
|
|
|
- How default-deny networking blocks all outbound traffic from a sandbox.
|
|
- How to apply a network policy that grants read-only access to a specific API.
|
|
- How L7 enforcement distinguishes between HTTP methods such as GET and POST on the same endpoint.
|
|
- How to inspect deny logs for a complete audit trail.
|
|
|
|
## Prerequisites
|
|
|
|
- A working OpenShell installation. Complete the [Quickstart](/get-started/quickstart) before proceeding.
|
|
- Docker Desktop running on your machine.
|
|
|
|
<Tip>
|
|
To run every step of this tutorial, you can also use the automated demo script at the [examples/sandbox-policy-quickstart](https://github.com/NVIDIA/OpenShell/blob/main/examples/sandbox-policy-quickstart) directory in the NVIDIA OpenShell repository. It runs the full walkthrough in under a minute but without any user interaction.
|
|
|
|
```shell
|
|
bash examples/sandbox-policy-quickstart/demo.sh
|
|
```
|
|
|
|
</Tip>
|
|
|
|
<Steps toc={true}>
|
|
|
|
## Create a Sandbox
|
|
|
|
Start by creating a sandbox with no network policies. This gives you a clean environment to observe default-deny behavior.
|
|
|
|
```shell
|
|
openshell sandbox create --name demo --no-auto-providers
|
|
```
|
|
|
|
`--no-auto-providers` skips the provider setup prompt since this tutorial uses `curl` instead of an AI agent.
|
|
|
|
You land in an interactive shell inside the sandbox:
|
|
|
|
```text
|
|
sandbox@demo:~$
|
|
```
|
|
|
|
## Try to Reach the GitHub API
|
|
|
|
With no network policy in place, every outbound connection is blocked. Test this by making a simple API call from inside the sandbox:
|
|
|
|
```shell
|
|
curl -s https://api.github.com/zen
|
|
```
|
|
|
|
`https://api.github.com/zen` is a lightweight, unauthenticated GitHub REST endpoint that returns a random aphorism on each call. It requires no tokens or parameters, which makes it a convenient smoke-test target for verifying outbound HTTPS connectivity.
|
|
|
|
The request fails. By default, all outbound network traffic is denied. The sandbox proxy intercepted the HTTPS CONNECT request to `api.github.com:443` and rejected it because no network policy authorizes `curl` to reach that host.
|
|
|
|
```text
|
|
curl: (56) Received HTTP code 403 from proxy after CONNECT
|
|
```
|
|
|
|
Exit the sandbox. Sandboxes are kept running by default, so you can reconnect later. Use `--no-keep` at creation time if you want the sandbox deleted after exit:
|
|
|
|
```shell
|
|
exit
|
|
```
|
|
|
|
## Check the Deny Log
|
|
|
|
Every denied connection produces a structured log entry. Query the sandbox logs from your host to confirm the denial and inspect the reason.
|
|
|
|
```shell
|
|
openshell logs demo --since 5m
|
|
```
|
|
|
|
You see a line like:
|
|
|
|
```text
|
|
action=deny dst_host=api.github.com dst_port=443 binary=/usr/bin/curl deny_reason="no matching network policy"
|
|
```
|
|
|
|
Every denied connection is logged with the destination, the binary that attempted it, and the reason. Nothing gets out silently.
|
|
|
|
## Apply a Read-Only GitHub API Policy
|
|
|
|
To allow the sandbox to reach the GitHub API, define a network policy that grants read-only access. The policy specifies which host, port, binary, and HTTP methods are permitted. Create a file called `github_readonly.yaml` with the following content:
|
|
|
|
```yaml
|
|
version: 1
|
|
|
|
filesystem_policy:
|
|
include_workdir: true
|
|
read_only: [/usr, /lib, /proc, /dev/urandom, /app, /etc, /var/log]
|
|
read_write: [/tmp, /dev/null]
|
|
landlock:
|
|
compatibility: best_effort
|
|
|
|
network_policies:
|
|
github_api:
|
|
name: github-api-readonly
|
|
endpoints:
|
|
- host: api.github.com
|
|
port: 443
|
|
protocol: rest
|
|
enforcement: enforce
|
|
access: read-only
|
|
binaries:
|
|
- { path: /usr/bin/curl }
|
|
```
|
|
|
|
The `filesystem_policy` and `landlock` sections preserve the default sandbox settings, while process identity is omitted so the active compute driver can select it. These sections are required because `policy set` replaces the entire policy. The `network_policies` section is the key part: `curl` can make GET, HEAD, and OPTIONS requests to `api.github.com` over HTTPS. Everything else is denied. The proxy auto-detects TLS on HTTPS endpoints and terminates it to inspect each HTTP request and enforce the `read-only` access preset at the method level.
|
|
|
|
Apply it:
|
|
|
|
```shell
|
|
openshell policy set demo --policy github_readonly.yaml --wait
|
|
```
|
|
|
|
`--wait` blocks until the sandbox confirms the new policy is loaded. No restart required. Policies are hot-reloaded.
|
|
|
|
<Tip>
|
|
This tutorial uses `curl` and `read-only` access to keep things simple. When building policies for real workloads:
|
|
|
|
- To scope the policy to an agent, replace the `binaries` section with your agent's binary, such as `/usr/local/bin/claude`, instead of `curl`.
|
|
- To grant write access, change `access: read-only` to `read-write` or add explicit `rules` for specific paths. Refer to the [Policy Schema](/reference/policy-schema).
|
|
- To allow additional endpoints, stack multiple policies in the same file for PyPI, npm, or your internal APIs. Refer to [Policies](/sandboxes/policies) for examples.
|
|
|
|
</Tip>
|
|
|
|
## Verify If GET Requests Are Allowed
|
|
|
|
The policy is now active. Reconnect to the sandbox and retry the same request to confirm that read access works.
|
|
|
|
```shell
|
|
openshell sandbox connect demo
|
|
```
|
|
|
|
Retry the same request:
|
|
|
|
```shell
|
|
curl -s https://api.github.com/zen
|
|
```
|
|
|
|
```text
|
|
Anything added dilutes everything else.
|
|
```
|
|
|
|
It works. The `read-only` preset allows GET requests through.
|
|
|
|
## Try a Write
|
|
|
|
The read-only preset allows GET but blocks mutating methods like POST, PUT, and DELETE. Test this by sending a POST request to the GitHub API while still inside the sandbox:
|
|
|
|
```shell
|
|
curl -s -X POST https://api.github.com/repos/octocat/hello-world/issues \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"title":"oops"}'
|
|
```
|
|
|
|
```json
|
|
{"error":"policy_denied","policy":"github-api-readonly","detail":"POST /repos/octocat/hello-world/issues not permitted by policy"}
|
|
```
|
|
|
|
The CONNECT request succeeded because `api.github.com` is allowed, but the L7 proxy inspected the HTTP method and returned `403`. `POST` is not in the `read-only` preset. An agent with this policy can read code from GitHub but cannot create issues, push commits, or modify anything.
|
|
|
|
Exit the sandbox:
|
|
|
|
```shell
|
|
exit
|
|
```
|
|
|
|
## Check the L7 Deny Log
|
|
|
|
L7 denials are logged separately from connection-level denials. The log entry includes the exact HTTP method and path that the proxy rejected.
|
|
|
|
```shell
|
|
openshell logs demo --level warn --since 5m
|
|
```
|
|
|
|
```text
|
|
l7_decision=deny dst_host=api.github.com l7_action=POST l7_target=/repos/octocat/hello-world/issues l7_deny_reason="POST /repos/octocat/hello-world/issues not permitted by policy"
|
|
```
|
|
|
|
The log captures the exact HTTP method, path, and deny reason. In production, pipe these logs to your SIEM for a complete audit trail of every request your agent makes.
|
|
|
|
<Tip>
|
|
To log violations without blocking requests, set `enforcement: audit` instead of `enforcement: enforce` in the policy. This is useful for building a policy iteratively: deploy in audit mode, review the logs, and switch to enforce when the rules are correct.
|
|
|
|
</Tip>
|
|
|
|
## Clean Up
|
|
|
|
Delete the sandbox to free resources. This stops all processes and purges any injected credentials.
|
|
|
|
```shell
|
|
openshell sandbox delete demo
|
|
```
|
|
|
|
<Tip>
|
|
To run this entire walkthrough non-interactively, use the automated demo script:
|
|
|
|
```shell
|
|
bash examples/sandbox-policy-quickstart/demo.sh
|
|
```
|
|
|
|
</Tip>
|
|
|
|
</Steps>
|
|
|
|
## Next Steps
|
|
|
|
- To walk through a full policy iteration with Claude Code, including diagnosing denials and applying fixes from outside the sandbox, refer to [GitHub Sandbox](/get-started/tutorials/github-sandbox).
|