Experiment, Fail, Learn, Repeat

Life is too exciting to just keep still!

Experimenting with IP Tables

While playing around with container technologies such as docker and kubernetes, one critical component that kind of comes up over and over again is the whole portion about managing network connections to the containers. If we are to just take an example of Kubernetes - the networking stack is handled by technologies that would interface with CNI as well kube proxy. In this post, we’ll be focusing on the linux feature that kube proxy kind of rely on (one of the modes that it runs on) which is IP Tables.

Introduction

According to wikipedia: “iptables is a user-space utility program that allows a system administrator to configure the IP packet filter rules of the Linux kernel firewall”.

There are multiple tables of concern with IPTables but we generally would only concern ourselves with 2 tables (NAT and FILTER). There are 5 different tables to manage but the rest of them are for more specific use cases. Refer to the following link for details https://wiki.archlinux.org/title/iptables:

  • NAT
  • FILTER
  • RAW
  • MANGLE
  • SECURITY
iptables -L -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
iptables -A INPUT -s "<IP ADDRESS>" -j DROP

Refer to the following reference: https://web.mit.edu/rhel-doc/4/RH-DOCS/rhel-rg-en-4/s1-iptables-options.html

Blocking access to nginx

iptables -A INPUT -p tcp --dport 80 -s X.X.X.X -j DROP

Block port 80 for source ip X.X.X.X by dropping the network packets for it. Alternatively, we can set it to “reject” the packets

iptables -A INPUT -p tcp --dport 80 -s X.X.X.X -j REJECT

Redirect port

iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80

From the following link: https://askubuntu.com/questions/444729/redirect-port-80-to-8080-and-make-it-work-on-local-machine
Packets meant for loopback interface don’t exactly go through PREROUTING chain

So, from external, it would work, but from inside, not really.

We would need to add the following command to make it with localhost:

iptables -t nat -A OUTPUT -o lo -p tcp --dport 8080 -j REDIRECT --to-port 80

Cleanup

A default GCE VM instance doesn’t have any initial ruleset for IPTables (it’s more governed by Google’s networking stack - managed by adding networking tags to Virtual Machines)

iptables -F
iptables -t nat -F

References

The following links can be useful when handling IPTables:

https://www.thegeekstuff.com/2011/06/iptables-rules-examples/

After install docker

(Still researching - do not use as reference)

Installing docker

sudo apt-get update
sudo apt-get install -y \
    ca-certificates \
    curl \
    gnupg \
    lsb-release
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target                      prot opt in     out     source               destination         
    0     0 DOCKER-USER                 all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 DOCKER-ISOLATION-STAGE-1    all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT                      all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 DOCKER                      all  --  *      docker0  0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT                      all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT                      all  --  docker0 docker0  0.0.0.0/0            0.0.0.0/0           

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER (1 references)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER-ISOLATION-STAGE-1 (1 references)
 pkts bytes target                      prot opt in         out         source               destination         
    0     0 DOCKER-ISOLATION-STAGE-2    all  --  docker0    !docker0    0.0.0.0/0            0.0.0.0/0           
    0     0 RETURN                      all  --  *          *           0.0.0.0/0            0.0.0.0/0           

Chain DOCKER-ISOLATION-STAGE-2 (1 references)
 pkts bytes target     prot opt in     out      source               destination         
    0     0 DROP       all  --  *      docker0  0.0.0.0/0            0.0.0.0/0           
    0     0 RETURN     all  --  *      *        0.0.0.0/0            0.0.0.0/0           

Chain DOCKER-USER (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0 
iptables -L -v -n -t nat
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
   49  7688 DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    1    60 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0           

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    1    60 DOCKER     all  --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0
docker run -d -p 8080:80 --name=lol nginx
Chain DOCKER (1 references)
 pkts bytes target     prot opt in          out         source      destination         
    0     0 ACCEPT     tcp  --  !docker0    docker0     0.0.0.0/0   172.17.0.2     tcp dpt:80
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    1    60 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0           
    0     0 MASQUERADE  tcp  --  *      *       172.17.0.2           172.17.0.2           tcp dpt:80

...

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
    0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8080 to:172.17.0.2:80
docker run -d --name=lol nginx
iptables -A DOCKER ! -i docker0 -o docker0 -p tcp --dport 80 -s 0.0.0.0/0 -d 172.17.0.2
iptables -t nat -j DNAT -A DOCKER -p tcp ! -i docker0 --dport 8080 --to-destination 172.17.0.2:80
iptables -t nat -j MASQUERADE -A POSTROUTING -s 172.17.0.2 -d 172.17.0.2 -p tcp --dport 80
iptables -D DOCKER 1
iptables -t nat -D DOCKER 2
iptables -t nat -D POSTROUTING 2
iptables -t nat -I PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80
iptables -t nat -I POSTROUTING -p tcp -s 172.17.0.2 -j SNAT --to 10.128.0.56


iptables -I DOCKER ! -o docker0 -p tcp --dport 80 -s 0.0.0.0/0 -d 172.17.0.2
iptables -t nat -A OUTPUT -o lo -p tcp --dport 30000 -j DNAT --to-destination 172.17.0.2:80