From cce3693980f340cbbdef4ec50e1c4b9eb4f88d87 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Tue, 2 Jun 2026 12:19:10 +0200 Subject: [PATCH 1/7] sbx: add org policy recipes page Add a governance page with minimal, composable network policy presets for common sandbox workflows (developer essentials, package registries, container images, Claude Code, Codex), in both Admin Console and Governance API form. Link it from the governance index. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../manuals/ai/sandboxes/governance/_index.md | 2 + .../ai/sandboxes/governance/recipes.md | 240 ++++++++++++++++++ 2 files changed, 242 insertions(+) create mode 100644 content/manuals/ai/sandboxes/governance/recipes.md diff --git a/content/manuals/ai/sandboxes/governance/_index.md b/content/manuals/ai/sandboxes/governance/_index.md index 5d7f4995540..516d96044af 100644 --- a/content/manuals/ai/sandboxes/governance/_index.md +++ b/content/manuals/ai/sandboxes/governance/_index.md @@ -38,6 +38,8 @@ personal account. machine with the `sbx policy` CLI - [Organization policy](org.md): centrally manage sandbox policies across your organization from the Admin Console +- [Org policy recipes](recipes.md): minimal, composable network policy presets + for common workflows, in Admin Console and API form - [Sign-in enforcement](sign-in-enforcement.md): require developers to sign in as organization members, enforced through endpoint management - [Monitoring](monitoring.md): inspect active rules and monitor sandbox diff --git a/content/manuals/ai/sandboxes/governance/recipes.md b/content/manuals/ai/sandboxes/governance/recipes.md new file mode 100644 index 00000000000..e0762efc25c --- /dev/null +++ b/content/manuals/ai/sandboxes/governance/recipes.md @@ -0,0 +1,240 @@ +--- +title: Org policy recipes +linkTitle: Policy recipes +weight: 22 +description: Minimal, composable network policy presets for common sandbox workflows, in Admin Console and API form. +keywords: docker sandboxes, governance, organization policy, network policy, allowlist, recipes, presets, Claude Code, Codex, package managers +--- + +Organization policies start deny-by-default: outbound traffic is blocked unless +an explicit allow rule matches, so every host or wildcard a workflow depends on +has to be added by hand. The recipes on this page are minimal starting points +you can copy, combine, and trim to fit your organization. + +These recipes are intentionally narrower than the local +[Balanced preset](local.md#default-preset). The Balanced preset is a catch-all +profile that allows a wide range of common developer destinations so individual +machines work out of the box. An organization policy should do the opposite: +allow only the destinations your organization actually wants its sandboxes to +reach. Treat each recipe as a baseline and remove anything you don't need. + +For the exact matching rules behind the resource patterns used here (exact +hostnames, single- and multi-level wildcards, port suffixes, and CIDR ranges), +see +[Policy concepts](concepts.md#network-rules). + +## How to apply a recipe + +Each recipe is a set of network allow rules. Apply them either from the Admin +Console or through the [Governance API](/reference/api/ai-governance/). + +### Admin Console + +In the [Admin Console](https://app.docker.com/admin), go to +**AI governance > Network access** and add the listed hostnames as allow rules. +You can paste multiple hostnames at once, one per line. Group related hosts into +a single rule with a descriptive name so the rule list stays readable. + +### API + +With the API, create a policy once, then add each block as a rule. The base URL +is `https://hub.docker.com/v2` and requests use a short-lived JWT obtained by +exchanging Docker Hub credentials. The examples use +[`jq`](https://jqlang.github.io/jq/) to extract IDs from the responses. + +```bash +# 1. Exchange a Docker Hub PAT or OAT for a bearer token. +TOKEN=$(curl -s -X POST https://hub.docker.com/v2/users/login \ + -H "Content-Type: application/json" \ + -d '{"username":"my-user","password":"dckr_pat_xxxxxxxx"}' | jq -r .token) + +# 2. Create an empty policy for the org and capture its ID. +POLICY_ID=$(curl -s -X POST \ + https://hub.docker.com/v2/orgs/my-org/governance/policies \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"name":"Claude Code — Node.js"}' | jq -r .id) +``` + +Each rule is then a single `POST` to the policy's `rules` sub-resource. Network +allow rules use the actions `connect:tcp` and `connect:udp` with +`"decision": "allow"`: + +```bash +curl -s -X POST \ + "https://hub.docker.com/v2/orgs/my-org/governance/policies/$POLICY_ID/rules" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Anthropic APIs", + "actions": ["connect:tcp", "connect:udp"], + "resources": ["api.anthropic.com", "statsig.anthropic.com", + "platform.claude.com", "downloads.claude.ai", "claude.com"], + "decision": "allow" + }' +``` + +The rest of the recipes list only the rule name and resources. Substitute them +into the `name` and `resources` fields of a request like the one above. Policy +changes take up to five minutes to reach developer machines. + +> [!NOTE] +> The only egress path out of a sandbox is the host HTTP/HTTPS proxy, so the +> resources below are all hostnames on ports 80 and 443. Where a host is +> reached over plain HTTP (OS package mirrors and certificate revocation +> endpoints), the port `:80` variant is listed explicitly; HTTPS-only hosts are +> listed without a port suffix. + +## Developer essentials + +Most sandboxes need a small baseline regardless of which agent or language they +run: a place to clone source from, the certificate infrastructure that TLS +handshakes validate against, and the OS package mirrors the base image installs +from. Start with this block and layer a language and agent recipe on top. + +### Source and version control + +| Rule name | Resources | +| --------- | --------------------------------------------------------- | +| GitHub | `github.com`, `**.github.com`, `**.githubusercontent.com` | + +Add `gitlab.com`, `**.gitlab.com`, or `bitbucket.org` only if your developers +host code there. + +### Certificate validation + +TLS clients fetch revocation and chain data from certificate authority +endpoints, many of which are served over plain HTTP on port 80. Without these, +some HTTPS handshakes stall or fail. This is a trimmed set covering the most +common authorities: + +| Rule name | Resources | +| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Certificate validation | `**.lencr.org`, `**.lencr.org:80`, `ocsp.digicert.com:80`, `cacerts.digicert.com:80`, `**.pki.goog`, `**.pki.goog:80`, `**.amazontrust.com`, `**.amazontrust.com:80` | + +### Operating system packages + +The default sandbox base image is Ubuntu, so `apt` reaches the Ubuntu mirrors +over both HTTP and HTTPS: + +| Rule name | Resources | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Ubuntu packages | `archive.ubuntu.com`, `archive.ubuntu.com:80`, `security.ubuntu.com`, `security.ubuntu.com:80`, `ports.ubuntu.com`, `ports.ubuntu.com:80`, `ubuntu.com` | + +If you build on a Debian base instead, add `debian.org` and `**.debian.org`. + +## Package registries + +Add only the registries for the languages your projects use. + +### Node.js and npm + +| Rule name | Resources | +| ------------ | ------------------------------------------------------------------------------ | +| npm registry | `registry.npmjs.org`, `npmjs.com`, `npmjs.org`, `nodejs.org`, `nodesource.com` | + +### Python and pip + +| Rule name | Resources | +| --------------- | ---------------------------------------------------------------------------------------- | +| Python packages | `pypi.org`, `files.pythonhosted.org`, `pythonhosted.org`, `pypa.io`, `bootstrap.pypa.io` | + +### Go modules + +| Rule name | Resources | +| ---------- | ---------------------------------------------------------------- | +| Go modules | `proxy.golang.org`, `sum.golang.org`, `golang.org`, `pkg.go.dev` | + +### Rust and Cargo + +| Rule name | Resources | +| ----------- | ------------------------------------------------------------------------------------------ | +| Rust crates | `crates.io`, `index.crates.io`, `static.crates.io`, `static.rust-lang.org`, `sh.rustup.rs` | + +## Container images + +If sandboxes pull container images, allow the registries you use. This block +covers Docker Hub and the most common public registries: + +| Rule name | Resources | +| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| Docker Hub | `docker.io`, `**.docker.io`, `docker.com`, `**.docker.com`, `production.cloudflare.docker.com`, `**.production.cloudflare.docker.com` | +| Other registries | `ghcr.io`, `gcr.io`, `**.gcr.io`, `mcr.microsoft.com`, `**.data.mcr.microsoft.com`, `quay.io`, `registry.k8s.io`, `public.ecr.aws` | + +## Agent rules + +Each coding agent talks to its own provider APIs. Add the block for the agents +your developers run, on top of the developer essentials and the relevant +language registries. + +### Claude Code + +| Rule name | Resources | +| -------------- | -------------------------------------------------------------------------------------------------------- | +| Anthropic APIs | `api.anthropic.com`, `statsig.anthropic.com`, `platform.claude.com`, `downloads.claude.ai`, `claude.com` | + +### Codex + +OpenAI's Codex CLI authenticates and streams completions through OpenAI hosts: + +| Rule name | Resources | +| ----------- | -------------------------------------------------------------------------------------------------------------------- | +| OpenAI APIs | `**.openai.com`, `chatgpt.com`, `**.chatgpt.com`, `**.oaistatic.com`, `**.oaiusercontent.com`, `cdn.openaimerge.com` | + +## Worked example: Claude Code on a Node.js project + +The following script builds a complete, minimal policy for developers running +Claude Code against Node.js projects hosted on GitHub. It combines the developer +essentials, the npm registry, and the Claude Code agent block. + +```bash +# Authenticate and create the policy. +TOKEN=$(curl -s -X POST https://hub.docker.com/v2/users/login \ + -H "Content-Type: application/json" \ + -d '{"username":"my-user","password":"dckr_pat_xxxxxxxx"}' | jq -r .token) + +POLICY_ID=$(curl -s -X POST \ + https://hub.docker.com/v2/orgs/my-org/governance/policies \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"name":"Claude Code — Node.js"}' | jq -r .id) + +# Add each block as a named rule. +add_rule() { + curl -s -X POST \ + "https://hub.docker.com/v2/orgs/my-org/governance/policies/$POLICY_ID/rules" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"name\":\"$1\",\"actions\":[\"connect:tcp\",\"connect:udp\"],\"resources\":$2,\"decision\":\"allow\"}" +} + +add_rule "GitHub" \ + '["github.com","**.github.com","**.githubusercontent.com"]' +add_rule "Certificate validation" \ + '["**.lencr.org","**.lencr.org:80","ocsp.digicert.com:80","cacerts.digicert.com:80","**.pki.goog","**.pki.goog:80","**.amazontrust.com","**.amazontrust.com:80"]' +add_rule "Ubuntu packages" \ + '["archive.ubuntu.com","archive.ubuntu.com:80","security.ubuntu.com","security.ubuntu.com:80","ubuntu.com"]' +add_rule "npm registry" \ + '["registry.npmjs.org","npmjs.com","npmjs.org","nodejs.org","nodesource.com"]' +add_rule "Anthropic APIs" \ + '["api.anthropic.com","statsig.anthropic.com","platform.claude.com","downloads.claude.ai","claude.com"]' +``` + +Verify the result with `sbx policy ls` on a developer machine (the policy shows +a `Governance: managed by ` header), or fetch the full policy from the API: + +```console +$ curl -s -H "Authorization: Bearer $TOKEN" \ + "https://hub.docker.com/v2/orgs/my-org/governance/policies/$POLICY_ID" | jq +``` + +## Related pages + +- [Organization policy](org.md): how org governance works and where rules are + configured +- [Policy concepts](concepts.md): resource model, rule syntax, and evaluation +- [AI Governance API](/reference/api/ai-governance/): full API reference +- [Monitoring](monitoring.md): inspect active rules and traffic with + `sbx policy ls` and `sbx policy log` + + From eff273da82a8524930a67425ba2c7a8f59d7dede Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Tue, 2 Jun 2026 12:30:40 +0200 Subject: [PATCH 2/7] sbx: reword source-host note, add monitoring cross-reference Reframe the GitLab/Bitbucket note as swapping GitHub for equivalent hosts, and point readers to sbx policy log / the Monitoring page for discovering which domains a workflow needs. Co-Authored-By: Claude Opus 4.8 (1M context) --- content/manuals/ai/sandboxes/governance/recipes.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/content/manuals/ai/sandboxes/governance/recipes.md b/content/manuals/ai/sandboxes/governance/recipes.md index e0762efc25c..fc86cecc5fe 100644 --- a/content/manuals/ai/sandboxes/governance/recipes.md +++ b/content/manuals/ai/sandboxes/governance/recipes.md @@ -18,6 +18,11 @@ machines work out of the box. An organization policy should do the opposite: allow only the destinations your organization actually wants its sandboxes to reach. Treat each recipe as a baseline and remove anything you don't need. +To work out exactly which hosts a workflow needs, run it in a sandbox and watch +the requests it makes with `sbx policy log`. Blocked destinations show up there, +so you can add the ones you want and leave the rest denied. See +[Monitoring](monitoring.md). + For the exact matching rules behind the resource patterns used here (exact hostnames, single- and multi-level wildcards, port suffixes, and CIDR ranges), see @@ -98,8 +103,9 @@ from. Start with this block and layer a language and agent recipe on top. | --------- | --------------------------------------------------------- | | GitHub | `github.com`, `**.github.com`, `**.githubusercontent.com` | -Add `gitlab.com`, `**.gitlab.com`, or `bitbucket.org` only if your developers -host code there. +If your developers host code elsewhere, swap GitHub for the equivalent hosts — +for example `gitlab.com` and `**.gitlab.com` for GitLab, or `bitbucket.org` for +Bitbucket. ### Certificate validation From 2ed19080102c1b282124490fed74412e9f32865e Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Tue, 2 Jun 2026 12:57:13 +0200 Subject: [PATCH 3/7] sbx: add ports.ubuntu.com to worked-example Ubuntu rule Match the worked example to the recipe table so ARM-based sandboxes can reach the Ubuntu ARM mirrors. Co-Authored-By: Claude Opus 4.8 (1M context) --- content/manuals/ai/sandboxes/governance/recipes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/manuals/ai/sandboxes/governance/recipes.md b/content/manuals/ai/sandboxes/governance/recipes.md index fc86cecc5fe..1c33a1fee8f 100644 --- a/content/manuals/ai/sandboxes/governance/recipes.md +++ b/content/manuals/ai/sandboxes/governance/recipes.md @@ -219,7 +219,7 @@ add_rule "GitHub" \ add_rule "Certificate validation" \ '["**.lencr.org","**.lencr.org:80","ocsp.digicert.com:80","cacerts.digicert.com:80","**.pki.goog","**.pki.goog:80","**.amazontrust.com","**.amazontrust.com:80"]' add_rule "Ubuntu packages" \ - '["archive.ubuntu.com","archive.ubuntu.com:80","security.ubuntu.com","security.ubuntu.com:80","ubuntu.com"]' + '["archive.ubuntu.com","archive.ubuntu.com:80","security.ubuntu.com","security.ubuntu.com:80","ports.ubuntu.com","ports.ubuntu.com:80","ubuntu.com"]' add_rule "npm registry" \ '["registry.npmjs.org","npmjs.com","npmjs.org","nodejs.org","nodesource.com"]' add_rule "Anthropic APIs" \ From 9197ff79017aa120d10803e55b920c2cf714ada6 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Tue, 2 Jun 2026 13:00:54 +0200 Subject: [PATCH 4/7] sbx: correct port-suffix semantics, use bare hostnames A rule without a port matches any port; only a :port suffix restricts. Reword the note accordingly and drop the redundant :80 entries, since bare hostnames already cover the HTTP and HTTPS ports the proxy handles. ports.ubuntu.com (bare) still covers the ARM mirror on port 80. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../ai/sandboxes/governance/recipes.md | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/content/manuals/ai/sandboxes/governance/recipes.md b/content/manuals/ai/sandboxes/governance/recipes.md index 1c33a1fee8f..50666707f52 100644 --- a/content/manuals/ai/sandboxes/governance/recipes.md +++ b/content/manuals/ai/sandboxes/governance/recipes.md @@ -84,11 +84,12 @@ into the `name` and `resources` fields of a request like the one above. Policy changes take up to five minutes to reach developer machines. > [!NOTE] -> The only egress path out of a sandbox is the host HTTP/HTTPS proxy, so the -> resources below are all hostnames on ports 80 and 443. Where a host is -> reached over plain HTTP (OS package mirrors and certificate revocation -> endpoints), the port `:80` variant is listed explicitly; HTTPS-only hosts are -> listed without a port suffix. +> A rule without a port suffix matches the host on any port. Add a `:port` +> suffix (for example, `example.com:443`) only when you want to restrict a host +> to a specific port. The recipes below use bare hostnames, which covers both +> the HTTP and HTTPS ports the sandbox proxy handles, so plain-HTTP services +> such as OS package mirrors and certificate endpoints work without listing +> `:80` separately. ## Developer essentials @@ -110,22 +111,23 @@ Bitbucket. ### Certificate validation TLS clients fetch revocation and chain data from certificate authority -endpoints, many of which are served over plain HTTP on port 80. Without these, -some HTTPS handshakes stall or fail. This is a trimmed set covering the most -common authorities: +endpoints, many of which are served over plain HTTP. Without these, some HTTPS +handshakes stall or fail. This is a trimmed set covering the most common +authorities: -| Rule name | Resources | -| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Certificate validation | `**.lencr.org`, `**.lencr.org:80`, `ocsp.digicert.com:80`, `cacerts.digicert.com:80`, `**.pki.goog`, `**.pki.goog:80`, `**.amazontrust.com`, `**.amazontrust.com:80` | +| Rule name | Resources | +| ---------------------- | ------------------------------------------------------------------------------------------------ | +| Certificate validation | `**.lencr.org`, `ocsp.digicert.com`, `cacerts.digicert.com`, `**.pki.goog`, `**.amazontrust.com` | ### Operating system packages -The default sandbox base image is Ubuntu, so `apt` reaches the Ubuntu mirrors -over both HTTP and HTTPS: +The default sandbox base image is Ubuntu, so `apt` reaches the Ubuntu mirrors. +`ports.ubuntu.com` is the mirror for non-x86 architectures, so ARM-based +sandboxes need it: -| Rule name | Resources | -| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Ubuntu packages | `archive.ubuntu.com`, `archive.ubuntu.com:80`, `security.ubuntu.com`, `security.ubuntu.com:80`, `ports.ubuntu.com`, `ports.ubuntu.com:80`, `ubuntu.com` | +| Rule name | Resources | +| --------------- | ----------------------------------------------------------------------------- | +| Ubuntu packages | `archive.ubuntu.com`, `security.ubuntu.com`, `ports.ubuntu.com`, `ubuntu.com` | If you build on a Debian base instead, add `debian.org` and `**.debian.org`. @@ -217,9 +219,9 @@ add_rule() { add_rule "GitHub" \ '["github.com","**.github.com","**.githubusercontent.com"]' add_rule "Certificate validation" \ - '["**.lencr.org","**.lencr.org:80","ocsp.digicert.com:80","cacerts.digicert.com:80","**.pki.goog","**.pki.goog:80","**.amazontrust.com","**.amazontrust.com:80"]' + '["**.lencr.org","ocsp.digicert.com","cacerts.digicert.com","**.pki.goog","**.amazontrust.com"]' add_rule "Ubuntu packages" \ - '["archive.ubuntu.com","archive.ubuntu.com:80","security.ubuntu.com","security.ubuntu.com:80","ports.ubuntu.com","ports.ubuntu.com:80","ubuntu.com"]' + '["archive.ubuntu.com","security.ubuntu.com","ports.ubuntu.com","ubuntu.com"]' add_rule "npm registry" \ '["registry.npmjs.org","npmjs.com","npmjs.org","nodejs.org","nodesource.com"]' add_rule "Anthropic APIs" \ From 92e976e8f9ae83643929b2877964d8c0ee71f889 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Fri, 5 Jun 2026 12:39:49 +0200 Subject: [PATCH 5/7] sbx: use /v2/auth/token endpoint in API recipes Replace deprecated /v2/users/login with /v2/auth/token, update request body fields from username/password to identifier/secret, and extract .access_token instead of .token from the response. Co-Authored-By: Claude Sonnet 4.6 --- content/manuals/ai/sandboxes/governance/recipes.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/manuals/ai/sandboxes/governance/recipes.md b/content/manuals/ai/sandboxes/governance/recipes.md index 50666707f52..24ed60c2682 100644 --- a/content/manuals/ai/sandboxes/governance/recipes.md +++ b/content/manuals/ai/sandboxes/governance/recipes.md @@ -49,9 +49,9 @@ exchanging Docker Hub credentials. The examples use ```bash # 1. Exchange a Docker Hub PAT or OAT for a bearer token. -TOKEN=$(curl -s -X POST https://hub.docker.com/v2/users/login \ +TOKEN=$(curl -s -X POST https://hub.docker.com/v2/auth/token \ -H "Content-Type: application/json" \ - -d '{"username":"my-user","password":"dckr_pat_xxxxxxxx"}' | jq -r .token) + -d '{"identifier":"my-user","secret":"dckr_pat_xxxxxxxx"}' | jq -r .access_token) # 2. Create an empty policy for the org and capture its ID. POLICY_ID=$(curl -s -X POST \ @@ -197,9 +197,9 @@ essentials, the npm registry, and the Claude Code agent block. ```bash # Authenticate and create the policy. -TOKEN=$(curl -s -X POST https://hub.docker.com/v2/users/login \ +TOKEN=$(curl -s -X POST https://hub.docker.com/v2/auth/token \ -H "Content-Type: application/json" \ - -d '{"username":"my-user","password":"dckr_pat_xxxxxxxx"}' | jq -r .token) + -d '{"identifier":"my-user","secret":"dckr_pat_xxxxxxxx"}' | jq -r .access_token) POLICY_ID=$(curl -s -X POST \ https://hub.docker.com/v2/orgs/my-org/governance/policies \ From bee8353f0b7ebc901bc3ff3a967429623e726be3 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Fri, 5 Jun 2026 12:42:52 +0200 Subject: [PATCH 6/7] sbx: link recipes Admin Console section to org.md#create-a-policy Co-Authored-By: Claude Sonnet 4.6 --- content/manuals/ai/sandboxes/governance/recipes.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/manuals/ai/sandboxes/governance/recipes.md b/content/manuals/ai/sandboxes/governance/recipes.md index 24ed60c2682..b44f75dd826 100644 --- a/content/manuals/ai/sandboxes/governance/recipes.md +++ b/content/manuals/ai/sandboxes/governance/recipes.md @@ -35,10 +35,10 @@ Console or through the [Governance API](/reference/api/ai-governance/). ### Admin Console -In the [Admin Console](https://app.docker.com/admin), go to -**AI governance > Network access** and add the listed hostnames as allow rules. -You can paste multiple hostnames at once, one per line. Group related hosts into -a single rule with a descriptive name so the rule list stays readable. +Follow the steps in [Create a policy](org.md#create-a-policy) to open the +**Network access** policy form. Add the listed hostnames as allow rules — you +can paste multiple hostnames at once, one per line. Group related hosts into a +single rule with a descriptive name so the rule list stays readable. ### API From df9d50a39b9d7e61e4342497ac269077254ba4ec Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 10 Jun 2026 15:48:41 +0200 Subject: [PATCH 7/7] sbx: restructure recipes as a phone-book lookup page Lead with a "Find a recipe" index, fold the auth/create-policy boilerplate into a single "Set up once" block that defines an add_rule helper, and make each recipe a self-contained entry with its hostnames visible inside one copyable command. Drop stray markup accidentally committed at the end of the file. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../ai/sandboxes/governance/recipes.md | 281 +++++++++--------- 1 file changed, 143 insertions(+), 138 deletions(-) diff --git a/content/manuals/ai/sandboxes/governance/recipes.md b/content/manuals/ai/sandboxes/governance/recipes.md index b44f75dd826..d850d5ed45e 100644 --- a/content/manuals/ai/sandboxes/governance/recipes.md +++ b/content/manuals/ai/sandboxes/governance/recipes.md @@ -7,48 +7,57 @@ keywords: docker sandboxes, governance, organization policy, network policy, all --- Organization policies start deny-by-default: outbound traffic is blocked unless -an explicit allow rule matches, so every host or wildcard a workflow depends on -has to be added by hand. The recipes on this page are minimal starting points -you can copy, combine, and trim to fit your organization. - -These recipes are intentionally narrower than the local -[Balanced preset](local.md#default-preset). The Balanced preset is a catch-all -profile that allows a wide range of common developer destinations so individual -machines work out of the box. An organization policy should do the opposite: -allow only the destinations your organization actually wants its sandboxes to -reach. Treat each recipe as a baseline and remove anything you don't need. - -To work out exactly which hosts a workflow needs, run it in a sandbox and watch -the requests it makes with `sbx policy log`. Blocked destinations show up there, -so you can add the ones you want and leave the rest denied. See -[Monitoring](monitoring.md). - -For the exact matching rules behind the resource patterns used here (exact -hostnames, single- and multi-level wildcards, port suffixes, and CIDR ranges), -see -[Policy concepts](concepts.md#network-rules). - -## How to apply a recipe - -Each recipe is a set of network allow rules. Apply them either from the Admin -Console or through the [Governance API](/reference/api/ai-governance/). +an explicit allow rule matches. The recipes on this page are minimal building +blocks for the hosts common workflows depend on — look up the ones you need, +check the hostnames, and copy them into a policy. + +Treat each recipe as a baseline, not a complete answer. They're intentionally +narrower than the local [Balanced preset](local.md#default-preset), which allows +a wide range of destinations so individual machines work out of the box. An +organization policy should do the opposite: allow only what your sandboxes +actually need, and remove anything you don't. To find the exact hosts a workflow +needs, run it in a sandbox and watch `sbx policy log` for blocked destinations. +See [Monitoring](monitoring.md). + +## Find a recipe + +- **Developer essentials**: [GitHub](#github) · + [Certificate validation](#certificate-validation) · + [Ubuntu packages](#ubuntu-packages) +- **Package registries**: [Node.js and npm](#nodejs-and-npm) · + [Python and pip](#python-and-pip) · [Go modules](#go-modules) · + [Rust and Cargo](#rust-and-cargo) +- **Container images**: [Docker Hub](#docker-hub) · + [Other registries](#other-container-registries) +- **Coding agents**: [Claude Code](#claude-code) · [Codex](#codex) + +Most sandboxes need the developer essentials regardless of language or agent: a +place to clone source from, certificate infrastructure for TLS, and OS package +mirrors. Layer a language registry and an agent recipe on top. + +## Apply a recipe + +Each recipe is a single network allow rule: a name and a list of host +resources. Apply them from the Admin Console or through the +[Governance API](/reference/api/ai-governance/). Policy changes take up to five +minutes to reach developer machines. ### Admin Console -Follow the steps in [Create a policy](org.md#create-a-policy) to open the -**Network access** policy form. Add the listed hostnames as allow rules — you -can paste multiple hostnames at once, one per line. Group related hosts into a -single rule with a descriptive name so the rule list stays readable. +Follow [Create a policy](org.md#create-a-policy) to open the **Network access** +policy form, then paste the hostnames from any recipe below as allow rules — one +per line. Group a recipe's hosts into a single rule and give it the recipe's +name so the rule list stays readable. ### API -With the API, create a policy once, then add each block as a rule. The base URL -is `https://hub.docker.com/v2` and requests use a short-lived JWT obtained by -exchanging Docker Hub credentials. The examples use -[`jq`](https://jqlang.github.io/jq/) to extract IDs from the responses. +Run the setup block once to get a token, create a policy, and define an +`add_rule` helper. Each recipe below is then a single call to that helper. The +base URL is `https://hub.docker.com/v2`, and the examples use +[`jq`](https://jqlang.github.io/jq/) to read IDs out of the responses. ```bash -# 1. Exchange a Docker Hub PAT or OAT for a bearer token. +# 1. Exchange a Docker Hub PAT or OAT for a short-lived bearer token. TOKEN=$(curl -s -X POST https://hub.docker.com/v2/auth/token \ -H "Content-Type: application/json" \ -d '{"identifier":"my-user","secret":"dckr_pat_xxxxxxxx"}' | jq -r .access_token) @@ -58,76 +67,63 @@ POLICY_ID=$(curl -s -X POST \ https://hub.docker.com/v2/orgs/my-org/governance/policies \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ - -d '{"name":"Claude Code — Node.js"}' | jq -r .id) -``` - -Each rule is then a single `POST` to the policy's `rules` sub-resource. Network -allow rules use the actions `connect:tcp` and `connect:udp` with -`"decision": "allow"`: + -d '{"name":"Sandbox network policy"}' | jq -r .id) -```bash -curl -s -X POST \ - "https://hub.docker.com/v2/orgs/my-org/governance/policies/$POLICY_ID/rules" \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "Anthropic APIs", - "actions": ["connect:tcp", "connect:udp"], - "resources": ["api.anthropic.com", "statsig.anthropic.com", - "platform.claude.com", "downloads.claude.ai", "claude.com"], - "decision": "allow" - }' +# 3. Helper that adds one network allow rule. Each recipe calls this. +add_rule() { + curl -s -X POST \ + "https://hub.docker.com/v2/orgs/my-org/governance/policies/$POLICY_ID/rules" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"name\":\"$1\",\"actions\":[\"connect:tcp\",\"connect:udp\"],\"resources\":$2,\"decision\":\"allow\"}" +} ``` -The rest of the recipes list only the rule name and resources. Substitute them -into the `name` and `resources` fields of a request like the one above. Policy -changes take up to five minutes to reach developer machines. - > [!NOTE] -> A rule without a port suffix matches the host on any port. Add a `:port` -> suffix (for example, `example.com:443`) only when you want to restrict a host -> to a specific port. The recipes below use bare hostnames, which covers both -> the HTTP and HTTPS ports the sandbox proxy handles, so plain-HTTP services -> such as OS package mirrors and certificate endpoints work without listing -> `:80` separately. +> The recipes use bare hostnames, with no `:port` suffix. A rule without a port +> suffix matches the host on any port, which covers both the HTTP and HTTPS +> ports the sandbox proxy handles — so plain-HTTP services such as OS package +> mirrors and certificate endpoints work without listing `:80` separately. Add a +> `:port` suffix (for example, `example.com:443`) only when you want to restrict +> a host to a specific port. For the full matching rules behind these patterns +> (exact hostnames, single- and multi-level wildcards, port suffixes, and CIDR +> ranges), see [Policy concepts](concepts.md#network-rules). ## Developer essentials -Most sandboxes need a small baseline regardless of which agent or language they -run: a place to clone source from, the certificate infrastructure that TLS -handshakes validate against, and the OS package mirrors the base image installs -from. Start with this block and layer a language and agent recipe on top. +### GitHub -### Source and version control +Clone and fetch source hosted on GitHub. -| Rule name | Resources | -| --------- | --------------------------------------------------------- | -| GitHub | `github.com`, `**.github.com`, `**.githubusercontent.com` | +```bash +add_rule "GitHub" \ + '["github.com","**.github.com","**.githubusercontent.com"]' +``` -If your developers host code elsewhere, swap GitHub for the equivalent hosts — -for example `gitlab.com` and `**.gitlab.com` for GitLab, or `bitbucket.org` for +If your developers host code elsewhere, swap in the equivalent hosts — for +example `gitlab.com` and `**.gitlab.com` for GitLab, or `bitbucket.org` for Bitbucket. ### Certificate validation -TLS clients fetch revocation and chain data from certificate authority -endpoints, many of which are served over plain HTTP. Without these, some HTTPS -handshakes stall or fail. This is a trimmed set covering the most common -authorities: +Revocation and chain data that TLS clients fetch from certificate authorities, +much of it served over plain HTTP. Without these, some HTTPS handshakes stall or +fail. This is a trimmed set covering the most common authorities. -| Rule name | Resources | -| ---------------------- | ------------------------------------------------------------------------------------------------ | -| Certificate validation | `**.lencr.org`, `ocsp.digicert.com`, `cacerts.digicert.com`, `**.pki.goog`, `**.amazontrust.com` | +```bash +add_rule "Certificate validation" \ + '["**.lencr.org","ocsp.digicert.com","cacerts.digicert.com","**.pki.goog","**.amazontrust.com"]' +``` -### Operating system packages +### Ubuntu packages -The default sandbox base image is Ubuntu, so `apt` reaches the Ubuntu mirrors. -`ports.ubuntu.com` is the mirror for non-x86 architectures, so ARM-based -sandboxes need it: +`apt` mirrors for the default Ubuntu base image. `ports.ubuntu.com` is the +mirror for non-x86 architectures, so ARM-based sandboxes need it. -| Rule name | Resources | -| --------------- | ----------------------------------------------------------------------------- | -| Ubuntu packages | `archive.ubuntu.com`, `security.ubuntu.com`, `ports.ubuntu.com`, `ubuntu.com` | +```bash +add_rule "Ubuntu packages" \ + '["archive.ubuntu.com","security.ubuntu.com","ports.ubuntu.com","ubuntu.com"]' +``` If you build on a Debian base instead, add `debian.org` and `**.debian.org`. @@ -137,85 +133,96 @@ Add only the registries for the languages your projects use. ### Node.js and npm -| Rule name | Resources | -| ------------ | ------------------------------------------------------------------------------ | -| npm registry | `registry.npmjs.org`, `npmjs.com`, `npmjs.org`, `nodejs.org`, `nodesource.com` | +npm package installs and the Node.js runtime. + +```bash +add_rule "npm registry" \ + '["registry.npmjs.org","npmjs.com","npmjs.org","nodejs.org","nodesource.com"]' +``` ### Python and pip -| Rule name | Resources | -| --------------- | ---------------------------------------------------------------------------------------- | -| Python packages | `pypi.org`, `files.pythonhosted.org`, `pythonhosted.org`, `pypa.io`, `bootstrap.pypa.io` | +pip installs and Python build backends. + +```bash +add_rule "Python packages" \ + '["pypi.org","files.pythonhosted.org","pythonhosted.org","pypa.io","bootstrap.pypa.io"]' +``` ### Go modules -| Rule name | Resources | -| ---------- | ---------------------------------------------------------------- | -| Go modules | `proxy.golang.org`, `sum.golang.org`, `golang.org`, `pkg.go.dev` | +`go` module downloads and checksum verification. + +```bash +add_rule "Go modules" \ + '["proxy.golang.org","sum.golang.org","golang.org","pkg.go.dev"]' +``` ### Rust and Cargo -| Rule name | Resources | -| ----------- | ------------------------------------------------------------------------------------------ | -| Rust crates | `crates.io`, `index.crates.io`, `static.crates.io`, `static.rust-lang.org`, `sh.rustup.rs` | +Cargo crate downloads and `rustup` toolchain installs. + +```bash +add_rule "Rust crates" \ + '["crates.io","index.crates.io","static.crates.io","static.rust-lang.org","sh.rustup.rs"]' +``` ## Container images -If sandboxes pull container images, allow the registries you use. This block -covers Docker Hub and the most common public registries: +Add only the registries your sandboxes pull from. + +### Docker Hub + +Pull images from Docker Hub. + +```bash +add_rule "Docker Hub" \ + '["docker.io","**.docker.io","docker.com","**.docker.com","production.cloudflare.docker.com","**.production.cloudflare.docker.com"]' +``` -| Rule name | Resources | -| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -| Docker Hub | `docker.io`, `**.docker.io`, `docker.com`, `**.docker.com`, `production.cloudflare.docker.com`, `**.production.cloudflare.docker.com` | -| Other registries | `ghcr.io`, `gcr.io`, `**.gcr.io`, `mcr.microsoft.com`, `**.data.mcr.microsoft.com`, `quay.io`, `registry.k8s.io`, `public.ecr.aws` | +### Other container registries -## Agent rules +Common public registries: GitHub, Google, Microsoft, Quay, Kubernetes, and AWS +public ECR. -Each coding agent talks to its own provider APIs. Add the block for the agents +```bash +add_rule "Other registries" \ + '["ghcr.io","gcr.io","**.gcr.io","mcr.microsoft.com","**.data.mcr.microsoft.com","quay.io","registry.k8s.io","public.ecr.aws"]' +``` + +## Coding agents + +Each coding agent talks to its own provider APIs. Add the recipe for the agents your developers run, on top of the developer essentials and the relevant language registries. ### Claude Code -| Rule name | Resources | -| -------------- | -------------------------------------------------------------------------------------------------------- | -| Anthropic APIs | `api.anthropic.com`, `statsig.anthropic.com`, `platform.claude.com`, `downloads.claude.ai`, `claude.com` | +Anthropic's Claude Code authenticates and streams completions through these +hosts. + +```bash +add_rule "Anthropic APIs" \ + '["api.anthropic.com","statsig.anthropic.com","platform.claude.com","downloads.claude.ai","claude.com"]' +``` ### Codex -OpenAI's Codex CLI authenticates and streams completions through OpenAI hosts: +OpenAI's Codex CLI authenticates and streams completions through OpenAI hosts. -| Rule name | Resources | -| ----------- | -------------------------------------------------------------------------------------------------------------------- | -| OpenAI APIs | `**.openai.com`, `chatgpt.com`, `**.chatgpt.com`, `**.oaistatic.com`, `**.oaiusercontent.com`, `cdn.openaimerge.com` | +```bash +add_rule "OpenAI APIs" \ + '["**.openai.com","chatgpt.com","**.chatgpt.com","**.oaistatic.com","**.oaiusercontent.com","cdn.openaimerge.com"]' +``` ## Worked example: Claude Code on a Node.js project -The following script builds a complete, minimal policy for developers running -Claude Code against Node.js projects hosted on GitHub. It combines the developer -essentials, the npm registry, and the Claude Code agent block. +A complete, minimal policy for developers running Claude Code against Node.js +projects hosted on GitHub combines the developer essentials, the npm registry, +and the Claude Code agent recipe. Run the [setup block](#api), then apply those +recipes: ```bash -# Authenticate and create the policy. -TOKEN=$(curl -s -X POST https://hub.docker.com/v2/auth/token \ - -H "Content-Type: application/json" \ - -d '{"identifier":"my-user","secret":"dckr_pat_xxxxxxxx"}' | jq -r .access_token) - -POLICY_ID=$(curl -s -X POST \ - https://hub.docker.com/v2/orgs/my-org/governance/policies \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"name":"Claude Code — Node.js"}' | jq -r .id) - -# Add each block as a named rule. -add_rule() { - curl -s -X POST \ - "https://hub.docker.com/v2/orgs/my-org/governance/policies/$POLICY_ID/rules" \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"name\":\"$1\",\"actions\":[\"connect:tcp\",\"connect:udp\"],\"resources\":$2,\"decision\":\"allow\"}" -} - add_rule "GitHub" \ '["github.com","**.github.com","**.githubusercontent.com"]' add_rule "Certificate validation" \ @@ -244,5 +251,3 @@ $ curl -s -H "Authorization: Bearer $TOKEN" \ - [AI Governance API](/reference/api/ai-governance/): full API reference - [Monitoring](monitoring.md): inspect active rules and traffic with `sbx policy ls` and `sbx policy log` - -