> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gravixlayer.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Network Policies

> Control which outbound destinations a sandbox can reach

By default a sandbox has **no outbound network access**. Attach a **network policy** when the workload must reach something outside the box — a public API, a package registry, or an internal system such as a database or private HTTP service.

```mermaid theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#EEF2FF','primaryTextColor':'#1E1B4B','primaryBorderColor':'#5B4CDB','lineColor':'#6366F1','secondaryColor':'#ECFDF5','secondaryBorderColor':'#00AD69','tertiaryColor':'#F5F3FF'}}}%%
flowchart LR
  A[Network policy] -->|attach| B[Runtime sandbox]
  B -->|outbound request| C{Policy check}
  C -->|allowed| D[Destination]
  C -->|blocked| E[Denied]
```

<Note>
  Manage policies on the **Network Policies** page in the platform (sidebar), or via `client.network_policies` / `/v1/network-policies`. This is separate from **Identity → Providers** (secrets).
</Note>

## Default egress posture

Every new runtime is fail-closed:

| Situation                  | Outbound access                                             |
| -------------------------- | ----------------------------------------------------------- |
| No network policy attached | **Blocked** — built-in system default is an empty allowlist |
| You attach an `allowlist`  | Only listed hosts/ports/protocols                           |
| You attach `allow_all`     | Broad outbound access (see note below)                      |
| You attach `denylist`      | Outbound allowed except listed destinations                 |
| You attach `deny_all`      | Blocked                                                     |

You do **not** start from “open internet.” You open only what the job needs.

The built-in **system default** is **hidden** from the Network Policies list and from `list_for_runtime` (use `include_system=True` to see it). It cannot be detached or deleted. Once you attach **any** network policy of your own, those policies define egress; the system default is only the fallback when nothing else is attached.

DNS needed to resolve hostnames still works under restrictive modes. Private / link-local / cloud metadata ranges stay blocked unless you explicitly allowlist that destination — including under `allow_all`.

## When outbound access is needed

Keep the default deny posture if the sandbox only runs local code, files, and shell. Attach a policy when the sandbox must call:

| Destination type         | Examples                                          | Typical rule                         |
| ------------------------ | ------------------------------------------------- | ------------------------------------ |
| Public HTTPS APIs        | LLM providers, SaaS webhooks, Git hosts           | hostname + port `443` + `tcp`        |
| Package registries       | PyPI, npm, container registries                   | hostname + `443`                     |
| Internal enterprise APIs | Private REST/gRPC behind your VPC or VPN hostname | hostname or private IP/CIDR + port   |
| Databases and raw TCP    | Postgres (`5432`), Redis (`6379`), Kafka, etc.    | hostname/IP + **exact port** + `tcp` |

List **every** destination the workload needs. An allowlist that includes only `api.openai.com` will block your internal DB — and an allowlist that includes only the DB will block the LLM API. To reach a private database or internal API under `allowlist`, add an explicit rule for that host (and port).

## Why attach a network policy?

| Goal                         | How network policies help                                                      |
| ---------------------------- | ------------------------------------------------------------------------------ |
| Call approved services only  | Allowlist the exact hosts and ports the agent needs                            |
| Reduce exfiltration risk     | Prompt injection cannot reach destinations you never opened                    |
| Reach private systems safely | Explicitly allow internal APIs or databases without opening the whole internet |
| Make intent reviewable       | Modes and rules document what the sandbox is allowed to touch                  |

Pair policies with [Identity Providers](/documentation/agentruntime/getting-started/identity-providers) so credentials are injected only for destinations you also allow.

## Enforced with eBPF

Network policies are enforced with **eBPF** in the Linux kernel — production-grade, battle-tested datapath enforcement used widely across cloud-native platforms.

That gives you:

| Benefit                        | What it means                                                          |
| ------------------------------ | ---------------------------------------------------------------------- |
| **Kernel-level enforcement**   | Decisions run in the datapath, not only in userspace proxies           |
| **Low overhead**               | Efficient filtering at scale without a heavy per-connection middleware |
| **Least privilege by default** | Deny-by-default posture with precise allow / deny rules                |
| **Battle-tested**              | eBPF network policy is widely deployed in production environments      |

You define *what* a sandbox may reach; eBPF enforces it on every outbound attempt.

## Egress modes

Every policy has an **egress mode**. Destination rules (host / IP / CIDR + port + protocol) apply to **allowlist** and **denylist**.

| Mode        | Behavior                                                                                                                               | Rules                      |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- |
| `allowlist` | **Default deny.** Only listed destinations are allowed. An empty rule list blocks all outbound traffic.                                | Required for useful access |
| `denylist`  | **Default allow.** Listed destinations are blocked; everything else is allowed.                                                        | Optional deny entries      |
| `allow_all` | Allow outbound traffic broadly. Cloud metadata and other sensitive private ranges remain blocked unless you explicitly allowlist them. | Ignored                    |
| `deny_all`  | Block all outbound traffic.                                                                                                            | Ignored                    |

Prefer **`allowlist`** for production agents. Use `allow_all` only when you truly need broad egress. Use `denylist` when most of the internet is fine but a few hosts must stay blocked.

### Rule shape

* **Destination** — hostname, IP, or CIDR
* **Port** — specific port, or `0` for any port
* **Protocol** — `tcp`, `udp`, or `any`

### Multiple policies

You can attach more than one network policy to a runtime. When that happens, the **most restrictive mode wins**:

| Precedence (highest → lowest)                       |
| --------------------------------------------------- |
| `deny_all` → `allowlist` → `denylist` → `allow_all` |

Examples:

* Any attached `deny_all` → no outbound access.
* Any `allowlist` (and no `deny_all`) → default deny; destinations from attached allowlists are allowed. If a denylist is also attached, overlapping destinations stay denied.
* Only `denylist` → outbound allowed except denied destinations.
* Only `allow_all` → broad outbound access (sensitive private/metadata ranges still blocked unless explicitly allowed).

Attaching a looser policy never weakens a stricter one — detach the stricter policy to open more egress.

Attach when creating a sandbox with `network_policy_ids=[...]`, or later with `attach(...)`. Rule changes and attach/detach apply to running sandboxes without recreate.

## Create a network policy with rules

Use an allowlist when the sandbox must reach both a public API and an internal system:

<CodeGroup>
  ```python Python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  from gravixlayer import GravixLayer

  client = GravixLayer()

  policy = client.network_policies.create(
      name="agent-egress",
      egress_mode="allowlist",
      description="LLM API + internal Postgres only",
      rules=[
          {
              "destination": "api.openai.com",
              "port": 443,
              "protocol": "tcp",
              "description": "OpenAI API",
          },
          {
              "destination": "db.internal.example.com",
              "port": 5432,
              "protocol": "tcp",
              "description": "Internal Postgres",
          },
      ],
  )
  print(policy.id, policy.egress_mode, policy.rule_count)
  ```

  ```bash cURL theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  curl -X POST "https://api.gravixlayer.ai/v1/network-policies" \
    -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "agent-egress",
      "egress_mode": "allowlist",
      "description": "LLM API + internal Postgres only"
    }'

  curl -X POST "https://api.gravixlayer.ai/v1/network-policies/POLICY_ID/rules" \
    -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "destination": "api.openai.com",
      "port": 443,
      "protocol": "tcp",
      "description": "OpenAI API"
    }'

  curl -X POST "https://api.gravixlayer.ai/v1/network-policies/POLICY_ID/rules" \
    -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "destination": "db.internal.example.com",
      "port": 5432,
      "protocol": "tcp",
      "description": "Internal Postgres"
    }'
  ```
</CodeGroup>

<Tip>
  In the Python SDK, `create(..., rules=[...])` creates the policy and adds rules in one call. If a rule fails, the policy is rolled back so you never keep a half-configured policy. For databases and other non-HTTP services, allow the **exact port** — do not rely on port `443` alone.
</Tip>

## Attach when creating a sandbox

<CodeGroup>
  ```python Python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  runtime = client.runtime.create(
      template="base-small",
      network_policy_ids=[policy.id],
  )

  # Allowed
  ok = runtime.run_cmd(
      "python",
      args=[
          "-c",
          "import socket; socket.create_connection(('api.openai.com', 443), 5); print('ok')",
      ],
      timeout=30,
  )
  print(ok.stdout.strip(), ok.exit_code)

  # Blocked under allowlist
  blocked = runtime.run_cmd(
      "python",
      args=[
          "-c",
          "import socket; socket.create_connection(('example.com', 443), 5); print('ok')",
      ],
      timeout=30,
  )
  print("blocked exit=", blocked.exit_code)
  ```

  ```bash cURL theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  curl -X POST "https://api.gravixlayer.ai/v1/agents/runtime" \
    -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "template": "base-small",
      "cloud": "azure",
      "region": "eastus2",
      "network_policy_ids": ["POLICY_ID"]
    }'
  ```
</CodeGroup>

## Attach to a running sandbox

<CodeGroup>
  ```python Python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  client.network_policies.attach(policy.id, runtime.runtime_id)

  attached = client.network_policies.list_for_runtime(runtime.runtime_id)
  for p in attached.policies:
      print(p.name, p.egress_mode, p.rule_count)
  ```

  ```bash cURL theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  curl -X POST "https://api.gravixlayer.ai/v1/network-policies/POLICY_ID/attach" \
    -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"runtime_id": "RUNTIME_ID"}'
  ```
</CodeGroup>

## List, get, and update a network policy

<CodeGroup>
  ```python Python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  listed = client.network_policies.list(limit=20, search="openai")
  detail = client.network_policies.get(policy.id, include_rules=True)
  for r in detail.rules or []:
      print(r.destination, r.port, r.protocol)

  policy = client.network_policies.update(
      policy.id,
      name="openai-only-prod",
      description="Production OpenAI allowlist",
  )
  ```

  ```bash cURL theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  curl "https://api.gravixlayer.ai/v1/network-policies?limit=20&search=openai" \
    -H "Authorization: Bearer $GRAVIXLAYER_API_KEY"

  curl "https://api.gravixlayer.ai/v1/network-policies/POLICY_ID" \
    -H "Authorization: Bearer $GRAVIXLAYER_API_KEY"

  curl "https://api.gravixlayer.ai/v1/network-policies/POLICY_ID/rules" \
    -H "Authorization: Bearer $GRAVIXLAYER_API_KEY"

  curl -X PATCH "https://api.gravixlayer.ai/v1/network-policies/POLICY_ID" \
    -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"name": "openai-only-prod", "description": "Production OpenAI allowlist"}'
  ```
</CodeGroup>

## Manage network policy rules

<CodeGroup>
  ```python Python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  rule = client.network_policies.add_rule(
      policy.id,
      destination="api.anthropic.com",
      port=443,
      protocol="tcp",
      description="Anthropic API",
  )

  rules = client.network_policies.list_rules(policy.id)

  client.network_policies.update_rule(
      policy.id,
      rule.id,
      description="Anthropic API (updated)",
  )

  client.network_policies.delete_rule(policy.id, rule.id)
  ```

  ```bash cURL theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  curl -X POST "https://api.gravixlayer.ai/v1/network-policies/POLICY_ID/rules" \
    -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "destination": "api.anthropic.com",
      "port": 443,
      "protocol": "tcp",
      "description": "Anthropic API"
    }'

  curl "https://api.gravixlayer.ai/v1/network-policies/POLICY_ID/rules" \
    -H "Authorization: Bearer $GRAVIXLAYER_API_KEY"

  curl -X PATCH "https://api.gravixlayer.ai/v1/network-policies/POLICY_ID/rules/RULE_ID" \
    -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"description": "Anthropic API (updated)"}'

  curl -X DELETE \
    "https://api.gravixlayer.ai/v1/network-policies/POLICY_ID/rules/RULE_ID" \
    -H "Authorization: Bearer $GRAVIXLAYER_API_KEY"
  ```
</CodeGroup>

## Detach and delete a network policy

<CodeGroup>
  ```python Python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  client.network_policies.detach(policy.id, runtime.runtime_id)
  runtime.kill()
  client.network_policies.delete(policy.id)
  ```

  ```bash cURL theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  curl -X DELETE \
    "https://api.gravixlayer.ai/v1/network-policies/POLICY_ID/attach/RUNTIME_ID" \
    -H "Authorization: Bearer $GRAVIXLAYER_API_KEY"

  curl -X DELETE "https://api.gravixlayer.ai/v1/network-policies/POLICY_ID" \
    -H "Authorization: Bearer $GRAVIXLAYER_API_KEY"
  ```
</CodeGroup>

## SDK reference

All network policy operations live under `client.network_policies` (maps to `/v1/network-policies`).

| Method                                               | Purpose                                          |
| ---------------------------------------------------- | ------------------------------------------------ |
| `create(...)`                                        | Create a policy (optional initial `rules`)       |
| `list(...)`                                          | List policies (built-in system default excluded) |
| `get(policy_id, include_rules=False)`                | Get one policy; optionally load rules            |
| `update(policy_id, ...)`                             | Update name, mode, description, or `is_active`   |
| `delete(policy_id)`                                  | Soft-delete the policy                           |
| `add_rule(policy_id, destination, ...)`              | Add a destination rule                           |
| `list_rules(policy_id)`                              | List rules                                       |
| `update_rule(policy_id, rule_id, ...)`               | Update a rule                                    |
| `delete_rule(policy_id, rule_id)`                    | Delete a rule                                    |
| `attach(policy_id, runtime_id)`                      | Attach to a runtime                              |
| `detach(policy_id, runtime_id)`                      | Detach from a runtime                            |
| `list_for_runtime(runtime_id, include_system=False)` | List policies on a runtime                       |

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
np = client.network_policies

# Policy CRUD
policies = np.list(limit=50)
policy = np.get(policy.id, include_rules=True)
np.update(policy.id, is_active=True)
np.delete(policy.id)

# Rules
np.add_rule(policy.id, destination="api.openai.com", port=443, protocol="tcp")
np.list_rules(policy.id)
np.update_rule(policy.id, rule_id, port=443)
np.delete_rule(policy.id, rule_id)

# Attach / detach
np.attach(policy.id, runtime.runtime_id)
np.list_for_runtime(runtime.runtime_id)
np.list_for_runtime(runtime.runtime_id, include_system=True)
np.detach(policy.id, runtime.runtime_id)
```

## Best practices

1. **Stay fail-closed by default** — only attach a network policy when outbound is required; prefer `allowlist` over `allow_all`.
2. **List every needed destination** — public APIs and internal hosts (DB, private API) must each have a rule under allowlist mode.
3. **Keep rules narrow** — hostname + exact port beats “any port”; avoid wide CIDRs unless necessary.
4. **Combine with secrets** — inject credentials via [Identity providers](/documentation/agentruntime/getting-started/identity-providers), and only allow the destinations those credentials should talk to.
5. **Detach when unused** — remove network policies from idle runtimes; delete unused policies.

<Warning>
  Network policies reduce blast radius; they do not stop malicious code from using destinations you intentionally allow. Pair them with least-privilege secrets and human review for high-risk actions.
</Warning>

## Next

<CardGroup cols={2}>
  <Card title="Web Services" icon="globe" href="/documentation/agentruntime/getting-started/web-services">
    Expose HTTP apps inside the runtime over HTTPS
  </Card>

  <Card title="Identity Providers" icon="key" href="/documentation/agentruntime/getting-started/identity-providers">
    Inject credentials as environment variables
  </Card>

  <Card title="Create Runtime" icon="play" href="/documentation/agentruntime/sandbox-management/create-sandbox">
    Attach policies at sandbox create
  </Card>
</CardGroup>
