如何通过iptables限制Kubernetes Pod访问外部MySQL服务的源IP
Hey there, let's tackle your two questions step by step, considering your specific cluster setup (Kubernetes 1.13.4, Calico overlay network, ipvs-mode kube-proxy, only ClusterIP services):
1. Restricting Source IP for Pods Accessing External Services
When pods in your Calico-overlay cluster access external services, traffic typically gets SNAT'ed to the node's IP by default. To control/limit the source IP, you have two reliable approaches:
Option 1: Use Calico's SNAT Policies (Recommended)
Calico lets you configure custom SNAT rules for outgoing traffic, which avoids conflicts with its own network management:
- Fixed single source IP: If you want all external-bound pod traffic to use a single IP (like a dedicated egress gateway), create a
GlobalNetworkPolicythat enforces SNAT to that IP. Example:apiVersion: projectcalico.org/v3 kind: GlobalNetworkPolicy metadata: name: egress-snat-fixed-ip spec: selector: all() egress: - action: Allow destination: nets: ["0.0.0.0/0"] # All external destinations nat: outboundIP: "192.168.1.100" # Your fixed egress IP - Per-node SNAT with controlled IP pool: If you want to restrict to a pool of node IPs, configure Calico's
felixsettings to only use specific node IPs for SNAT. You can set this via the Calico ConfigMap:# Update calico-config ConfigMap data: felix-config: | { "snatOutgoing": true, "outgoingIPs": ["192.168.1.20", "192.168.1.21"] # Allowed node SNAT IPs }
Option 2: Node-level iptables Rules (Use with Caution)
Since Calico manages node iptables rules, you'll need to add your rules to a chain that Calico won't overwrite (like INPUT or FORWARD with higher priority):
- For example, to SNAT all pod traffic from a specific namespace to a fixed IP:
Note: This needs to be applied to all nodes, and you'll need to maintain it if Calico resets iptables rules.# Get the pod CIDR for your target namespace (or use pod IPs directly) POD_CIDR=$(kubectl get namespace my-app -o jsonpath='{.metadata.annotations.cni.projectcalico.org/ipv4pools}') # Add SNAT rule iptables -t nat -A POSTROUTING -s $POD_CIDR -d 0.0.0.0/0 -j SNAT --to-source 192.168.1.100
2. Restricting VM-hosted MySQL Access to Specific Pods via iptables
Your DBA's requirement is achievable, but you first need to fix a key routing issue: by default, pods accessing the external VM will have their source IP replaced with the node's IP (due to SNAT). To target individual pods, you need to make the pod's overlay IP visible to the VM. Here's how:
Step 1: Enable Direct Pod IP Routing to the VM
Calico uses BGP for network routing—you can add the VM (or its upstream router) as a BGP peer to your Calico cluster. This lets the VM directly route traffic to pod IPs, so pod traffic to the VM will retain its original pod IP as the source.
- Edit your Calico BGP configuration to add the VM's IP as a peer:
apiVersion: projectcalico.org/v3 kind: BGPPeer metadata: name: vm-peer spec: peerIP: "10.0.0.50" # VM's IP address asNumber: 64512 # Use the same AS number as your Calico cluster (default is 64512) - Verify the VM can ping a pod IP to confirm routing works.
Step 2: Configure iptables Rules on the VM
Once the VM can see pod IPs, you can create strict iptables rules to allow only specific pods:
- First, set a default deny rule for MySQL's port (3306):
iptables -A INPUT -p tcp --dport 3306 -j DROP - Then add allow rules for your target pod IPs:
# Allow pod 10.233.64.10 iptables -I INPUT -p tcp --dport 3306 -s 10.233.64.10 -j ACCEPT # Allow pod 10.233.64.11 iptables -I INPUT -p tcp --dport 3306 -s 10.233.64.11 -j ACCEPT - Save the rules to persist across VM reboots:
# On Debian/Ubuntu iptables-save > /etc/iptables/rules.v4 # On RHEL/CentOS service iptables save
Workaround If BGP Routing Isn't Possible
If you can't add the VM as a BGP peer, you can use node-level SNAT to assign a unique source IP to traffic from your target pods, then allow that IP on the VM:
- On every cluster node, add an iptables rule to SNAT traffic from your target pods to a dedicated IP:
# Replace with your pod IP range or specific pod IPs iptables -t nat -A POSTROUTING -s 10.233.64.0/24 -d 10.0.0.50/32 --dport 3306 -j SNAT --to-source 192.168.1.200 - On the VM, allow only this dedicated IP:
Note: You'll need to update these rules if pods are recreated and their IPs change—using Calico's static IP assignment for critical pods avoids this hassle.iptables -I INPUT -p tcp --dport 3306 -s 192.168.1.200 -j ACCEPT iptables -A INPUT -p tcp --dport 3306 -j DROP
内容的提问来源于stack exchange,提问作者Alex.Lee

