---
title: "Network Security Layers"
description: "Defense in depth for network security from host firewalls through service mesh mTLS to zero-trust networking in Kubernetes."
url: https://agent-zone.ai/knowledge/security/network-security-layers/
section: knowledge
date: 2026-02-22
categories: ["security"]
tags: ["network-security","network-policies","mtls","service-mesh","zero-trust","wireguard","firewall"]
skills: ["network-policy-design","service-mesh-mtls","firewall-management","zero-trust-networking"]
tools: ["iptables","nftables","kubectl","istio","linkerd","wireguard"]
levels: ["intermediate"]
word_count: 786
formats:
  json: https://agent-zone.ai/knowledge/security/network-security-layers/index.json
  html: https://agent-zone.ai/knowledge/security/network-security-layers/?format=html
  api: https://api.agent-zone.ai/api/v1/knowledge/search?q=Network+Security+Layers
---


## Defense in Depth

No single network control stops every attack. Layer controls so that a failure in one does not compromise the system: host firewalls, Kubernetes network policies, service mesh encryption, API gateway authentication, and DNS security, each operating independently.

## Host Firewall: iptables and nftables

Every node should run a host firewall regardless of the orchestrator. Block everything by default:

```bash
# iptables: default deny with essential allows
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# Allow established connections
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow SSH from management network only
iptables -A INPUT -p tcp --dport 22 -s 10.0.100.0/24 -j ACCEPT

# Allow kubelet API (for k8s nodes)
iptables -A INPUT -p tcp --dport 10250 -s 10.0.0.0/16 -j ACCEPT

# Allow loopback
iptables -A INPUT -i lo -j ACCEPT
```

The nftables equivalent is more readable for complex rulesets:

```bash
nft add table inet filter
nft add chain inet filter input '{ type filter hook input priority 0; policy drop; }'
nft add rule inet filter input ct state established,related accept
nft add rule inet filter input tcp dport 22 ip saddr 10.0.100.0/24 accept
nft add rule inet filter input iif lo accept
```

On Kubernetes nodes, do not block inter-pod or CNI overlay traffic. The CNI plugin manages its own iptables rules. Host rules should focus on node-level services.

## Kubernetes Network Policies

By default, every pod can talk to every other pod. Network policies restrict this. They require a CNI that supports them (Calico, Cilium, Weave). Flannel alone does not enforce network policies.

### Deny All by Default

Start with a default-deny policy in each namespace, then allow specific traffic:

```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
```

This blocks all ingress and egress for every pod in the namespace. Nothing works until you add allow rules.

### Allow Specific Traffic

```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-api
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api-server
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - protocol: TCP
          port: 8080
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-egress-to-database
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api-server
  policyTypes:
    - Egress
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: postgres
      ports:
        - protocol: TCP
          port: 5432
    - to:  # Allow DNS resolution
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
```

Critical: if you restrict egress, you must explicitly allow DNS (UDP 53 to kube-dns). Without it, service name resolution fails silently.

### Namespace Isolation

```yaml
ingress:
  - from:
      - namespaceSelector:
          matchLabels:
            network-access: monitoring
        podSelector:
          matchLabels:
            app: prometheus
```

This allows only pods labeled `app: prometheus` from namespaces labeled `network-access: monitoring` to reach the target pods.

## Service Mesh mTLS

Network policies control which pods can connect but do not encrypt traffic or verify caller identity. A service mesh adds mutual TLS automatically.

### Istio Strict mTLS

```yaml
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: default
  namespace: production
spec:
  mtls:
    mode: STRICT
```

All meshed traffic must be mTLS. Envoy handles certificate rotation and encryption transparently. Applications see plaintext on localhost.

### Linkerd

Linkerd enables mTLS by default with no configuration. Once the proxy is injected, all meshed traffic is encrypted. Verify with:

```bash
linkerd viz stat deploy -n production
```

The `SECURED` column shows the percentage of traffic using mTLS.

## API Gateway Authentication

The edge of your network needs authentication before requests reach internal services. Common patterns:

**OAuth2/OIDC** for user-facing APIs. The gateway validates JWT tokens against the identity provider. Envoy, Kong, and NGINX all support this.

**API keys** for machine-to-machine calls between external partners and your services. Rate-limit per key and rotate regularly.

**mTLS at the gateway** for high-security integrations. The client presents a certificate signed by your CA. This provides both encryption and client identity without passwords or tokens.

## DNS Security

DNS is often overlooked. An attacker who poisons DNS responses redirects traffic to malicious endpoints. **DNSSEC** signs responses so clients verify integrity. **DNS-over-TLS** encrypts queries to prevent eavesdropping. Within Kubernetes, ensure CoreDNS is not exposed outside the cluster and its RBAC is minimally scoped.

## VPN and Bastion Hosts

Cluster API servers and node SSH should never be public. **WireGuard** creates encrypted tunnels with minimal attack surface:

```bash
# On the bastion/gateway
wg set wg0 peer <client-public-key> allowed-ips 10.0.200.2/32

# On the client
wg set wg0 peer <server-public-key> endpoint bastion.example.com:51820 \
  allowed-ips 10.0.0.0/16
```

**Bastion hosts** are hardened jump boxes in a DMZ. Log all sessions. Use certificate-based SSH only.

## Zero-Trust Principles for Kubernetes

Zero trust means no implicit trust based on network location. Apply these principles: verify identity on every request (service mesh mTLS), authorize every action (RBAC and network policies), encrypt all traffic, log and audit everything, and assume breach (namespace isolation, least-privilege service accounts). Each layer above contributes. No single tool achieves zero trust alone.

