Iptables basic forward before messing things up

Hello,

I would like to allow a connection from the internet to port 10022 (host) → 22 SSH to my container. The port from the internet should be 10022 because my host already uses tcp port 22 for ssh.

My current config for iptables is:

iptables -S      
-P INPUT DROP
-P FORWARD DROP
-P OUTPUT DROP
-N f2b-sshd
-A INPUT -i lxdbr0 -p tcp -m tcp --dport 53 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A INPUT -i lxdbr0 -p udp -m udp --dport 53 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A INPUT -i lxdbr0 -p udp -m udp --dport 67 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A INPUT -p tcp -m multiport --dports 22 -j f2b-sshd
-A INPUT -i lo -j ACCEPT
-A INPUT -s 127.0.0.0/8 -j DROP
-A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -p udp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -p icmp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m set --match-set ipset_subnet-de src -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m set --match-set ipset_subnet-at src -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m set --match-set ipset_subnet-ch src -j ACCEPT
-A FORWARD -o lxdbr0 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A FORWARD -i lxdbr0 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A OUTPUT -o lxdbr0 -p tcp -m tcp --sport 53 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A OUTPUT -o lxdbr0 -p udp -m udp --sport 53 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A OUTPUT -o lxdbr0 -p udp -m udp --sport 67 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT
-A f2b-sshd -j RETURN

Unfortunately I was not able to find an article that describes my requirement, especially not with the pre-defined rules "script comment generated for LXD network lxdbr0.

Before I create a mess and build a security hole I would like to ask if the rules for my requirements are correct ?

iptables -A FORWARD -i enp4s0 -d <container-ip> -p tcp --dport 22 -j ACCEPT
iptables -A FORWARD -i enp4s0 -j DROP

iptables -A FORWARD -i lxdbr0 -m state --state NEW,INVALID -j DROP

iptables -t nat -A PREROUTING -p tcp --dport 10022 -j DNAT --to <container-ip>:22

Is this correct or did I something completely stupid ?
What would be the correct way if I need fail2ban for port 10022 ?

BR

In the meantime I tried my rules but I was not able the container SSH service.

iptables -S
-P INPUT DROP
-P FORWARD DROP
-P OUTPUT DROP
-N f2b-sshd
-A INPUT -i lxdbr0 -p tcp -m tcp --dport 53 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A INPUT -i lxdbr0 -p udp -m udp --dport 53 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A INPUT -i lxdbr0 -p udp -m udp --dport 67 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A INPUT -p tcp -m multiport --dports 22 -j f2b-sshd
-A INPUT -i lo -j ACCEPT
-A INPUT -s 127.0.0.0/8 -j DROP
-A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -p udp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -p icmp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m set --match-set ipset_subnet-de src -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m set --match-set ipset_subnet-at src -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m set --match-set ipset_subnet-ch src -j ACCEPT
-A FORWARD -o lxdbr0 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A FORWARD -i lxdbr0 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A FORWARD -d 10.251.253.69/32 -i enp4s0 -p tcp -m tcp --dport 22 -j ACCEPT
-A FORWARD -i enp4s0 -j DROP
-A FORWARD -i lxdbr0 -m state --state INVALID,NEW -j DROP
-A OUTPUT -o lxdbr0 -p tcp -m tcp --sport 53 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A OUTPUT -o lxdbr0 -p udp -m udp --sport 53 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A OUTPUT -o lxdbr0 -p udp -m udp --sport 67 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT
-A f2b-sshd -j RETURN

I am not sure what I did wrong but for me the rules are looking good.
Does anyone have an idea ?

Unfortunately I am completely lost. After hours and hours of testing, trying to narrow down the issue setting up things, reverting it I am not able to allow a connection. Even when I set a simple python webserver within the container listen on simple TCP 8080.

I found out that after I added the following line I am able to reach the webserver from the host to the container

lxc config device add container1 test8080 proxy listen=tcp:0.0.0.0:8080 connect=tcp:127.0.0.1:8080  

I am not able to connect to the service from the outside internet.

Is there a simple book or example in order to understand the way to configure iptables to forward traffic to the container ?

Hi Marc,
If I catch the post correctly, you need to make a NAT connection on the host side with the iptable rules and make a proxy connection on the related container. On the container,
lxc config device add container1 test10022 proxy listen=tcp:0.0.0.0:10022 connect=tcp:0.0.0.0:22
may work. But be sure, on the container you listen 0.0.0.0 not 127.0.0.1 on the ssh port.
I hope, that might give an idea.
Regards.

Hello cemzafer,

thank you for your help.

I already tested it wirh a NAT rule but it didn’t work.

iptables -t nat -A PREROUTING -p tcp --dport 10022 -j DNAT --to <container-ip>:22

Maybe there is something wrong with the policy.

Hi,
I mean, if you are behind the firewall/router then you just need to port forwarding to your host and then in the host just define the proxy could be enough. No need to NAT on the host again.
You can test flushing the iptables rules with the sudo iptables -F command on the host.
Regards.

If I understand you correct I don’t need a NAT rule if I use the "lxc config device add " command. I just need to allow iptables to allow connection to the host. Am I correct ?

Do I need to allow the connection to the host via INPUT or via FORWARD chain ?

Yes thats correct, first you can flush all the iptable rules (iptables -F) to make sure on the host then on the container define the proxy rule with the following command.
lxc config device add container1 test10022 proxy listen=tcp:0.0.0.0:10022 connect=tcp:0.0.0.0:22

You dont need to do that rule/rules, just flush all the iptable rules and test it then you can make your firewall rules more persistent.

Regards.

You dont need to do that rule/rules, just flush all the iptable rules and test it then you can make your firewall rules more persistent.

If I flush the rules I would have (depending on the default chain settings for input, output and forward) no iptables rule at all which means no service would be blocked or am I wrong ?

Can you post the output of the sudo iptables -L?

Yes you are correct.

Can you post the output of the sudo iptables -L ?

I created a python webserver within the container on TCP port 8080. After I added the following command line.

lxc config device add container1 test8080 proxy listen=tcp:0.0.0.0:8080 connect=tcp:127.0.0.1:8080
iptables -L
Chain INPUT (policy DROP)
target     prot opt source               destination         
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:domain /* generated for LXD network lxdbr0 */
ACCEPT     udp  --  anywhere             anywhere             udp dpt:domain /* generated for LXD network lxdbr0 */
ACCEPT     udp  --  anywhere             anywhere             udp dpt:bootps /* generated for LXD network lxdbr0 */
ACCEPT     all  --  anywhere             anywhere            
DROP       all  --  localhost/8          anywhere            
ACCEPT     tcp  --  anywhere             anywhere             state ESTABLISHED
ACCEPT     udp  --  anywhere             anywhere             state ESTABLISHED
ACCEPT     icmp --  anywhere             anywhere             state ESTABLISHED
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh state NEW match-set ipset_subnet-de src
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh state NEW match-set ipset_subnet-at src
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh state NEW match-set ipset_subnet-ch src

Chain FORWARD (policy DROP)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             /* generated for LXD network lxdbr0 */
ACCEPT     all  --  anywhere             anywhere             /* generated for LXD network lxdbr0 */

Chain OUTPUT (policy DROP)
target     prot opt source               destination         
ACCEPT     tcp  --  anywhere             anywhere             tcp spt:domain /* generated for LXD network lxdbr0 */
ACCEPT     udp  --  anywhere             anywhere             udp spt:domain /* generated for LXD network lxdbr0 */
ACCEPT     udp  --  anywhere             anywhere             udp spt:bootps /* generated for LXD network lxdbr0 */
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     tcp  --  anywhere             anywhere             state NEW,ESTABLISHED
ACCEPT     udp  --  anywhere             anywhere             state NEW,ESTABLISHED
ACCEPT     icmp --  anywhere             anywhere             state NEW,ESTABLISHED
iptables -L -t nat                              
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  10.215.253.0/24     !10.215.253.0/24      /* generated for LXD network lxdbr0 */
iptables -S
-P INPUT DROP
-P FORWARD DROP
-P OUTPUT DROP
-A INPUT -i lxdbr0 -p tcp -m tcp --dport 53 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A INPUT -i lxdbr0 -p udp -m udp --dport 53 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A INPUT -i lxdbr0 -p udp -m udp --dport 67 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -s 127.0.0.0/8 -j DROP
-A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -p udp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -p icmp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m set --match-set ipset_subnet-de src -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m set --match-set ipset_subnet-at src -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m set --match-set ipset_subnet-ch src -j ACCEPT
-A FORWARD -o lxdbr0 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A FORWARD -i lxdbr0 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A OUTPUT -o lxdbr0 -p tcp -m tcp --sport 53 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A OUTPUT -o lxdbr0 -p udp -m udp --sport 53 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A OUTPUT -o lxdbr0 -p udp -m udp --sport 67 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT

I am able to connect to the service within the container from the host

nc -v -z 127.0.0.1 8080                                                                                                                                                             130 ⨯
Connection to 127.0.0.1 8080 port [tcp/http-alt] succeeded!

You can change chain policy from DROP to ACCEPT and test it with that state, but as I mentioned before you forward your port traffic from your router to host first.
Regards.

Ok, I allowed TCP Port 8080 via INPUT chain and I was able to connect to the TCP port 8080 within the container.

Thank you very much.

In general, is the “lxc config device add … proxy” method really the prefered method in terms of security ?

You are welcome.

Non technical answer is yes. :slight_smile:
Regards.

Probably the easier way to achieve this is using the proxy device, e.g.

lxc config device add <instance> myproxy proxy listen=tcp:0.0.0.0:10022 connect=tcp:127.0.0.1:22

You need to make sure you don’t have a firewall on the host blocking inbound connections to port 1022 and that you have an SSH service listening on the 127.0.0.1 port 22 address inside the container.

This will use a separate proxy process to forwarding connections from the host to the container, and will allow it to listen on the wildcard (0.0.0.0) address on the host and connect to the loopback (127.0.0.1) address inside the container.

The downside of this approach is that your application will not see the remote IP that is connecting.
See Instances | LXD

The alternative is to use NAT mode by adding nat=true to the command above, which will then use iptables/nftables DNAT rules to, but this will require your instance’s NIC has a static IP, by setting ipv4.address on it, and you will need to specify a specific listen address rather than 0.0.0.0.