Create a Post
ChristianCastil
Employee
Employee

AKS network with CloudGuard VMSS

I want to present an architecture to solve some needs that came to my mind when use AKS in Azure and try to apply egress policy per pod or ingress threat prevention from within other Azure vNETs or Internet.

First, we will understand that AKS is the K8S Control plane offer from MS in Azure and uses VM as worker nodes, this allows the user to easy deploy K8S clusters and the Worker Nodes are deployed in their own vNETs.

This solution came with two offering in Networking the traditional Kubenet and Azure CNI.

Kubenet: will deploy each node with an IP from the Azure vNET but each Pod will have an IP only inside the cluster and Services take care to NAT it for ingress exposing trough Azure LB or Worker Node will NAT Hide for egress.  This is the default CNI for AKS and many implementations.  The flow in this offer will look like this.

ChristianCastil_4-1648162138403.png

 

Azure CNI: this option provides integration with the underlying Azure vNET, all Pods are created with a direct IP address from the vNET where the worker reside (there is a Preview feature that allows selecting a different subnet, but for the purposes of this posting that do not worked).  Now this means that the Pod have an external IP from the cluster and the flow will look like this.

 ChristianCastil_5-1648162148737.png

 

Now to protect this I'll deploy a VMSS from Check Point and use Hub and Spoke topology to centralize the networking and create a point of contact outside of the vNET, the Spoke vNETs will send the traffic to the Check Point Gateways by Route Tables and allows the communication between vNETs with rules in the gateways.

 
 

aks.png

 

Now when investigating inside the logs I saw that AKS send me the packets with the NAT Hide of the Worker Node, even when each Pod has an IP address from the AKS Subnet.

Digging found IPtables is used and the rules that applies NAT masquerade looks like this.

 

 

 

 

 

 

 

 

 

sudo iptables -t nat -nvL POSTROUTING

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
14204  860K KUBE-POSTROUTING  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */
    0     0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0
14190  860K IP-MASQ-AGENT  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* ip-masq-agent: ensure nat POSTROUTING directs all non-LOCAL destination traffic to our custom IP-MASQ-AGENT chain */ ADDRTYPE match dst-type !LOCAL

 

 

 

 

 

 

 

 

 

 

The KUBE-POSTROUTING chain has just a Return the MASQUERADE chain has no effect, since just apply for any outside docker and all reach the IP-MAQ-AGENT chain, this one looks like this.

 

 

 

 

 

 

 

 

 

sudo iptables -t nat -nvL IP-MASQ-AGENT

Chain IP-MASQ-AGENT (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 RETURN     all  --  *      *       0.0.0.0/0            10.100.0.0/16        /* ip-masq-agent: local traffic is not subject to MASQUERADE */
   14   911 MASQUERADE  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* ip-masq-agent: outbound traffic is subject to MASQUERADE (must be last in chain) */

 

 

 

 

 

 

 

 

 

the chain matches the block from the vNET as return and anything else MASQUERADE that means NAT Hide, so that's happening 

Now let's check who is managing this rules from Kubernetes, since all this should be orchestrated;

 

 

 

 

 

 

 

 

 

# Lets check for any ip-masq pods in kube-system
kubectl get pods -n kube-system -o wide|grep ip-masq
azure-ip-masq-agent-g2dsn                    1/1     Running   0          4h52m   10.100.0.4    aks-nodepool1-44430483-vmss000000   <none>           <none>
azure-ip-masq-agent-j27xx                    1/1     Running   0          

# Now lets see if there are configmaps we can look at
kubectl get configmaps -n kube-system|grep ip-masq
azure-ip-masq-agent-config           1      4h55m

 

 

 

 

 

 

 

 

 

 

So that configmap is the one that administrate the ip-masq-agent pod, if we check it we see an interesting data with nonmasqueradeCIDR

 

 

 

 

 

 

 

 

 

kubectl get configmap azure-ip-masq-agent-config -n kube-system -o yaml
apiVersion: v1
data:
  ip-masq-agent: |-
    nonMasqueradeCIDRs:
      - 10.100.0.0/16
      - 10.0.0.0/8
    masqLinkLocal: true
    resyncInterval: 60s
kind: ConfigMap

 

 

 

 

 

 

 

 

 

 

So if we add the 0.0.0.0/0 or any other vNET CIDR to the list it will change at IPTABLES chain level

 

 

 

 

 

 

 

 

 

# Edit the config map and add a row to the nonMasqueradeCIDRS
# I know...kubectl edit is evil...but we're just playing around here
kubectl edit configmap azure-ip-masq-agent-config -n kube-system

# Check the config
kubectl get configmap azure-ip-masq-agent-config -n kube-system -o yaml
apiVersion: v1
data:
  ip-masq-agent: |-
    nonMasqueradeCIDRs:
      - 10.100.0.0/16
      - 10.100.0.0/16
      - 10.0.0.0/8
      - 0.0.0.0/0

# Now lets see if that impacted our iptables
sudo iptables -t nat -nvL IP-MASQ-AGENT

Chain IP-MASQ-AGENT (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 RETURN     all  --  *      *       0.0.0.0/0            10.100.0.0/16        /* ip-masq-agent: local traffic is not subject to MASQUERADE */
    0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0          /* ip-masq-agent: local traffic is not subject to MASQUERADE */

 

 

 

 

 

 

 

 

 

 

This change make me see the Pod IP in the Logs of the Check Point instead of the Node IP, so now we can create rules per Pod.

I'll attach a video showing the live logs and config.

(1)
1 Reply
Shay_Levin
Admin
Admin

@ChristianCastil as always, great stuff!

0 Kudos