firewall-networking · git:20260610.5ee9b17 · 2026-06-10 · sha256 60db8c5882631eed
firewall-networking git:20260610.5ee9b17A
Immutable. This exact content never changes and is served at /api/v1/blob/60db8c5882631eed.
---
name: firewall-networking
description: "Firewall rules and service-to-service communication on Control Plane. Use when the user asks about inbound/outbound rules, CIDR whitelisting, IP blocking, hostname filtering, geo-blocking, header routing, internal endpoints, or network security."
---
# Firewall & Networking Patterns
Deep firewall rules for `spec.firewallConfig`. The deny-by-default summary, the LB picker, internal DNS, and which tool sets `firewallConfig` vs `loadBalancer` live in the `workload` skill — this skill is the detail.
**Precedence (both inbound and outbound):** blocked CIDRs beat allowed CIDRs; when both CIDR and hostname allow-lists are set, CIDR rules beat hostname rules.
## External Firewall Rules
### Inbound (internet → workload)
Allow all (`0.0.0.0/0`), or list specific CIDRs, and block CIDRs that override the allow-list:
```yaml
firewallConfig:
external:
inboundAllowCIDR:
- 0.0.0.0/0 # or specific: 203.0.113.0/24, 198.51.100.10/32
inboundBlockedCIDR:
- 192.0.2.0/24 # blocked wins over allowed
```
### Outbound (workload → internet)
CIDR allow/block (CIDR-based allows all ports):
```yaml
firewallConfig:
external:
outboundAllowCIDR:
- 0.0.0.0/0
outboundBlockedCIDR:
- 10.0.0.0/8 # blocked wins over allowed
```
Hostname allow-list (wildcard prefix supported). **Hostname rules only allow ports 80, 443, and 445 by default** — widen with `outboundAllowPort`:
```yaml
firewallConfig:
external:
outboundAllowHostname:
- api.stripe.com
- "*.amazonaws.com"
```
### Outbound Port Control
`outboundAllowPort` restricts which ports are allowed (protocols: `http`, `https`, `tcp`):
```yaml
firewallConfig:
external:
outboundAllowCIDR:
- 203.0.113.0/24
outboundAllowPort:
- protocol: tcp
number: 5432
- protocol: https
number: 8443
```
### Header-Based Filtering (Inbound HTTP)
Each filter matches a header `key` with either `allowedValues` (allow-list) or `blockedValues` (block-list) — **never both on the same filter**. Combine multiple filters, each on a different key:
```yaml
firewallConfig:
external:
inboundAllowCIDR:
- 0.0.0.0/0
http:
inboundHeaderFilter:
- key: x-api-version # allow-list: reject everything else for this header
allowedValues:
- "^v2$"
- key: user-agent # block-list: allow everything else
blockedValues:
- "^BadBot.*$"
- "^Scraper.*$"
```
**Header filter values are RE2 regular expressions.** Use `^...$` to match whole strings; a bare substring matches partially (`^bar$` vs. `bar` which also matches `barbell`). When multiple values are listed, the filter matches if **any** value matches — not all.
### Geo-Filtering (Country / Region / City)
**Two-step setup:** enable geo headers on the load balancer with custom header names, then filter on those names in `inboundHeaderFilter`:
```yaml
spec:
loadBalancer:
geoLocation:
enabled: true
headers:
country: x-country
region: x-region
city: x-city
asn: x-asn
firewallConfig:
external:
inboundAllowCIDR:
- 0.0.0.0/0
http:
inboundHeaderFilter:
- key: x-country
allowedValues:
- United States
- Canada
```
- You choose the header names; the workload receives the resolved values on each request.
- At least one of `asn`, `city`, `country`, or `region` must be configured; header names must be **unique** per type.
- Geo filtering only affects workloads with an HTTP port; no effect on TCP-only workloads.
## Internal Firewall (Workload-to-Workload)
`inboundAllowType` is one of `none`, `same-gvc`, `same-org`, `workload-list`. For `workload-list`, name the allowed workloads (cross-GVC supported):
```yaml
firewallConfig:
internal:
inboundAllowType: workload-list # or: none, same-gvc, same-org
inboundAllowWorkload:
- //gvc/my-gvc/workload/frontend
- //gvc/other-gvc/workload/backend
```
## Service-to-Service Communication
Internal DNS form: `http://WORKLOAD.GVC.cpln.local:PORT` (plain HTTP — the sidecar adds mTLS automatically, never `https://`):
```bash
curl http://api-service.my-gvc.cpln.local:8080/health # same-GVC: free, low latency
curl http://shared-service.other-gvc.cpln.local:3000/data # cross-GVC: needs same-org, egress charges
```
## Load Balancers (Summary)
| Type | Scope | Custom Ports | Static IPs | Wildcard Hosts |
|---|---|---|---|---|
| Default (shared) | All workloads | No (HTTP/HTTPS on 80/443) | No | No |
| Direct | Per-workload | Yes (TCP/UDP/HTTP/HTTPS/WS) | Via IP Set | No |
| Dedicated | Per-GVC | Yes | Via IP Set | Yes |
Minimal Direct LB (custom TCP port, per workload):
```yaml
spec:
loadBalancer:
direct:
enabled: true
ports:
- externalPort: 5432
protocol: TCP
containerPort: 5432
```
Full LB config, static IP reservation, and dedicated LB setup: see the **cpln-ipset-load-balancing** skill.
## Quick Reference
### Recommended: MCP
`firewallConfig` (and `loadBalancer`) live in the workload spec — patch them with the typed workload tools:
1. `mcp__cpln__get_resource` (kind="workload") — read current `spec.firewallConfig` / `spec.loadBalancer` for a rollback baseline (`update_workload` is PATCH — only sent fields change).
2. `mcp__cpln__update_workload` — set `firewallConfig` (external inbound/outbound, internal, header filters). Load balancer is separate: `mcp__cpln__configure_workload_load_balancer`.
3. `mcp__cpln__list_deployments` — poll until ready; rules apply within about a minute and trigger a new deployment.
Use `mcp__cpln__create_workload` to stand up a new workload with firewall rules from the start. Reserve static IPs for Direct/Dedicated LBs with `mcp__cpln__create_ipset` / `mcp__cpln__get_resource` (kind="ipset") (see **cpln-ipset-load-balancing**).
### Fallback: CLI
When MCP is unavailable or unauthenticated, edit the manifest and apply it. Ground the spec shape with `mcp__cpln__get_resource_schema` (or `cpln workload --help`) first:
```bash
cpln workload get WORKLOAD_NAME --gvc GVC_NAME -o yaml > workload.yaml
# edit spec.firewallConfig in workload.yaml
cpln apply --file workload.yaml --gvc GVC_NAME
```
### MCP Tools
| Tool | Purpose |
|---|---|
| `mcp__cpln__get_resource` (kind="workload") | Inspect current `spec.firewallConfig` and `spec.loadBalancer` before changing them. |
| `mcp__cpln__update_workload` | Patch `firewallConfig` on an existing workload (PATCH — only sent fields change). |
| `mcp__cpln__configure_workload_load_balancer` | Set/clear the workload load balancer (direct, geo headers, replicaDirect). |
| `mcp__cpln__create_workload` | Create a new workload with firewall rules from the start (load balancer is set separately). |
| `mcp__cpln__create_ipset` / `mcp__cpln__get_resource` (kind="ipset") | Reserve and inspect static public IPs for Direct/Dedicated load balancers and IP allow-lists. |
| `mcp__cpln__list_deployments` | Poll deployment readiness after a firewall change lands. |
| `mcp__cpln__get_workload_logs` | Query workload logs to diagnose connectivity issues. |
### Related Skills
- **cpln-workload** — Start here: the primary workload skill (types, defaults, spec shape) that routes here for firewall & exposure.
- **cpln-cdn-rate-limiting** — CDN setup, caching policies, and rate limiting configuration
- **cpln-ipset-load-balancing** — Static IP reservation, Direct and Dedicated load balancer configuration, and domain routing
- **cpln-native-networking** — PrivateLink, Private Service Connect, and agent-based private connectivity
- **cpln-workload-security** — JWT authentication, mTLS, and direct load balancer security configuration
## Documentation
- [Firewall Reference](https://docs.controlplane.com/reference/workload/firewall.md)
- [Load Balancing Reference](https://docs.controlplane.com/reference/workload/load-balancing.md)
- [Service-to-Service Guide](https://docs.controlplane.com/guides/service-to-service.md)
- [GVC Reference](https://docs.controlplane.com/reference/gvc.md)