mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-04 08:28:19 +08:00
The tutorial told users to exit the sandbox and reconnect later, but exiting the interactive shell stops the sandbox's main process and it is not reconnectable under the default restart policy. Switch to the two-terminal flow already used by the github-sandbox tutorial so the sandbox stays running, matching what examples/sandbox-policy-quickstart/ demo.sh actually does. Related: #2998, #2798 Signed-off-by: Russell Bryant <rbryant@redhat.com>
208 lines
8.5 KiB
Plaintext
208 lines
8.5 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
|
|
```
|
|
|
|
Leave this sandbox shell open and switch to a second terminal on your host for the next steps. The remaining `openshell` commands (checking logs and applying the policy) run on your host, not inside the sandbox.
|
|
|
|
<Note>
|
|
Keep the interactive sandbox shell open for the rest of the tutorial. Exiting it stops the sandbox's main process, and with the default restart policy the sandbox is not reconnectable afterward. Add `--no-keep` at creation time if you want the sandbox deleted automatically when you exit.
|
|
|
|
</Note>
|
|
|
|
## Check the Deny Log
|
|
|
|
Every denied connection produces a structured log entry. In your second (host) terminal, query the sandbox logs 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. Return to your sandbox shell in the first terminal (it is still running) and retry the same request to confirm that read access works:
|
|
|
|
```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.
|
|
|
|
## 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. Run this from your second (host) terminal, leaving the sandbox shell open:
|
|
|
|
```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).
|