FirewallPolicy CRDs, enforced at the VNet boundary by
the Aviatrix spoke gateway. When a server is removed, its policy is removed with
it.
For the business case and architecture overview, see MCP Server Security
Through Containment Architecture. For the complete Terraform reference
implementation, see the
obot-mcp-egress-azure blueprint.

Prerequisites
- Aviatrix Controller 8.2 or later
- CoPilot 4.31 or later
- DCF for Kubernetes enabled with Log Enrichment turned on
- A cloud account onboarded in CoPilot for the Azure subscription hosting the AKS cluster
- Obot 0.21.0 or later (earlier versions do not include MCPNetworkPolicy support)
Procedure
- CoPilot UI
- Terraform
Deploy an Aviatrix spoke gateway in the cluster VPC
- In CoPilot, navigate to Cloud Fabric > Gateways > Spoke Gateways and click + Spoke Gateway.
-
Provide the following details:
- In the Instances section, select a subnet in the cluster VPC for the gateway instance.
- Click Save.
Confirm network topology
Disable Azure IP masquerade
ip-masq-agent rewrites pod source IPs to node IPs before outbound
traffic reaches the spoke gateway. Aviatrix SmartGroups resolve to pod IPs, so
masqueraded traffic does not match Kubernetes label selectors and FirewallPolicy
rules have no effect.Apply the following ConfigMap to disable SNAT for all external destinations:Install the Aviatrix Kubernetes Firewall Helm chart
<chart-version> with the current chart version from the
Aviatrix k8s-firewall-charts repository:Verify Aviatrix CRD installation
Onboard the Kubernetes cluster to Aviatrix DCF
- Navigate to Cloud Resources > Cloud Assets > Kubernetes Clusters.
- Click Onboard next to the target cluster.
-
Choose the appropriate access method for your cloud provider:
- AWS (EKS): Select Terraform or Command Line, apply the generated access entry and RBAC configuration, check the confirmation box, then click Onboard.
- Azure (AKS): Select Permissions on Cloud Account if the Aviatrix service principal has the required permissions, or Kubeconfig File to upload a kubeconfig. Click Onboard.
- Wait for the cluster status to show Yes (green) on the Kubernetes Clusters tab.
view-nodes ClusterRole so the Controller can discover
node metadata. The CoPilot onboarding dialog generates the required YAML
automatically — apply it before clicking Onboard.Configure V1 DCF policies and default deny
aks-subnet: source for infrastructure rules- Match type: CIDR
- CIDR: the AKS node subnet address range (for example,
10.0.0.0/24)
k8s-api-server: Kubernetes API server public IP- Match type: CIDR
- CIDR: the AKS API server public IP as a /32 (for example,
1.2.3.4/32)
az aks show -n <cluster> -g <rg> --query fqdn -o tsv | xargs hostobot-system: Obot orchestration pods- Match type: Kubernetes
- Namespace: the Obot system namespace (for example,
obot-system)
aks-infra-egress: AKS infrastructure domains required by all nodes and
podsobot-pod-egress: domains required by Obot orchestration podscharts.obot.ai,api.anthropic.com,github.com,*.github.com,raw.githubusercontent.com,*.githubusercontent.com
kubernetes.default.svc is DNAT’d by kube-proxy to the AKS API server’s
public IP. TLS over an IP address has no SNI field in the ClientHello, so
WebGroup domain matching skips it. Without this rule, all pods lose Kubernetes
API access when default deny takes effect.FirewallPolicy PERMIT rules generated by
the network policy controller.Configure Obot with the Aviatrix network policy provider
aviatrix-network-policy-controller chart into the cluster automatically.<npc-version> with the current chart version from
charts.obot.ai.OBOT_SERVER_MCPDEFAULT_DENY_ALL_EGRESS=true ensures any MCP server deployed
without declared egress domains starts with zero outbound access. Without this
setting, servers with no egress declaration inherit the environment’s default
posture.After the upgrade, verify the network policy controller is running:firewallpolicies.networking.aviatrix.com and
webgrouppolicies.networking.aviatrix.com) must be present before the network
policy controller starts. If the controller pod shows a CrashLoopBackOff
with a no matches for kind FirewallPolicy error, re-run the k8s-firewall
Helm install from the earlier step.Declare egress destinations per MCP server
api.github.com and *.githubusercontent.com.Via the Obot API:- Bare hostname or leading wildcard only:
api.example.comor*.example.com - No protocols, paths, ports, or IP addresses
localhost,*.svc, and bare*are rejected- Empty
egressDomainswithOBOT_SERVER_MCPDEFAULT_DENY_ALL_EGRESS=trueresults in zero outbound access for that server
FirewallPolicy CRD targeting that server’s pods. Inspect generated policies:obot-<mnp-id>-fw. Pod labels use an
internal server ID (app: <server-id>, for example app: ms16mfzb), not the
human-readable server name. This is expected.Verify containment
-
Deploy an MCP server through Obot and confirm a
FirewallPolicywas generated: -
Check that the policy was applied successfully:
A successful apply produces an event with
Reason: UpdatePolicyListSuccess. - In CoPilot, navigate to Security > Distributed Cloud Firewall and select the cluster. Confirm the server’s containment policy appears with the correct egress allow-list.
- To confirm egress blocking is active, attempt a connection from an MCP server pod to a destination not in its declared domains and verify it is denied. In CoPilot per-connection logs, a denied connection appears with Action: Deny. If no entry appears within a few seconds, verify that the spoke gateway is in the egress data path for the cluster’s node subnet.