Proxmox – Block Incoming Traffic to Proxmox Hosts on Standard Ports Like SSH/22 and Use Non Standard Ports Instead

Problem

There are good reasons that you might want a specific service to listen to a port number that is different from the “standard” port. By standard I mean like port 22 for SSH or 80 for HTTP. Like when you have multiple webserverers running on the same host that cannot share port 80 with each other. Or if you want to “hide” your service from all the automatic script attacks that focus on standard ports. The latter is the motivation for the following scenario:

I have a Proxmox host. That host should not be accessable via SSH on the standard port 22 (TCP). Instead it should be port 10022. Because of the way Proxmox works you cannot just change the listening port of the SSH deamon from 22 to 10022. Also because there is no firewall/router in front of that host that could take over the port mapping (10022 -> Router -> 22 -> Proxmox) it has to be accomplished by the Proxmox host itself.

Solution

My way to achieve the goal is to configure netfilter with the help of itables. I will show you two different flavours in terms of network interfaces that are used to fulfill our needs. But before we start the following preconditions must be met:

The cluster firewall

  • allows exceptions for port 10022 and as long as this walkthrough lasts two exceptions for the ports 22/8006 to avoid locking ourselves out of the system unexpectedly
  • drops incoming traffic by default
  • is turned OFF until we finish the walkthrough
Proxmox: Settings for the datacenter firewall to enable incoming traffic on port 10022
Proxmox: Settings for the datacenter firewall to enable incoming traffic on port 10022

Flavour 1: Only use the build in Linux bridge vmbr0

WARNING: From a security standpoint this is not the best solution unless you really know what you’re doing. Read on to get to know why.

On your Proxmox host open the the interfaces configuration file:

$ sudo nano /etc/network/interfaces

Alter the vmbr0 part as follows:

auto vmbr0
iface vmbr0 inet static
        address 192.168.2.190/24
        gateway 192.168.2.1
        bridge-ports enp0s3
        bridge-stp off
        bridge-fd 0
        post-up         echo 1 > /proc/sys/net/ipv4/ip_forward
        post-up         echo 1 > /proc/sys/net/ipv4/conf/all/route_localnet
        post-up         iptables -I INPUT -i vmbr0 -p tcp -d 192.168.2.190 --dport 22 -j DROP
        post-down       iptables -D INPUT -i vmbr0 -p tcp -d 192.168.2.190 --dport 22 -j DROP
        post-up         iptables -t nat -A PREROUTING -p tcp --dport 10022 -j DNAT --to-destination 127.0.0.1:22
        post-down       iptables -t nat -D PREROUTING -p tcp --dport 10022 -j DNAT --to-destination 127.0.0.1:22
        post-up         iptables -I FORWARD -p tcp -d 127.0.0.1 --dport 22 -j ACCEPT
        post-down       iptables -D FORWARD -p tcp -d 127.0.0.1 --dport 22 -j ACCEPT
        post-up         iptables -I INPUT -i lo -p tcp --dport 22 -j ACCEPT
        post-down       iptables -D INPUT -i lo -p tcp --dport 22 -j ACCEPT

So what do we have here… let’s see.

The first part is nothing special, just adapt:

address 192.168.2.190/24
gateway 192.168.2.1
bridge-ports enp0s3
bridge-stp off
bridge-fd 0

Then make sure, whenever this interface comes up (post-up directive), that the flag to enable forwarding of IP packets is set:

post-up         echo 1 > /proc/sys/net/ipv4/ip_forward

Also make sure that local routing is enabled:

post-up         echo 1 > /proc/sys/net/ipv4/conf/all/route_localnet

Since local routing is enabled we can use the localhost to be the receiver of the packets that came in on the public IP address on port 10022. We change them to be delvered to localhost on port 22 (the SSH deamon on Proxmox is by default listening not only on the public but also on the local address):

# Enable destination NATting from incoming addresses on port 10022 to localhost on port 22
post-up         iptables -t nat -A PREROUTING -p tcp --dport 10022 -j DNAT --to-destination 127.0.0.1:22
post-down       iptables -t nat -D PREROUTING -p tcp --dport 10022 -j DNAT --to-destination 127.0.0.1:22

# Allow forwarding of traffic from the public address to the local one
post-up         iptables -I FORWARD -p tcp -d 127.0.0.1 --dport 22 -j ACCEPT
post-down       iptables -D FORWARD -p tcp -d 127.0.0.1 --dport 22 -j ACCEPT

# Allow incoming traffic on the localhost interface for the port 22
post-up         iptables -I INPUT -i lo -p tcp --dport 22 -j ACCEPT
post-down       iptables -D INPUT -i lo -p tcp --dport 22 -j ACCEPT

As you might recognized I left out a rule from above. This one is optional and will force blocking traffic on port 22 to the Proxmox host:

post-up         iptables -I INPUT -i vmbr0 -p tcp -d 192.168.2.190 --dport 22 -j DROP
post-down       iptables -D INPUT -i vmbr0 -p tcp -d 192.168.2.190 --dport 22 -j DROP

By default certain network traffic that originates from the same “management” subnet that the Proxmox host is a part of (in my case 192.168.2.0/24) will be allowed to pass firewall rules. It will be blocked if it comes from the outside world but not from within the management subnet. If you’re fine with that skip the rule.

Now apply the network changes (see this post for a little helper script):

$ sudo cp /etc/network/interfaces /etc/network/interfaces.new
$ sudo systemctl restart networking.service

Flavour 2: Use a dedicated Linux bridge

Now instead of reusing the vmbr0 bridge, let’s create a new one (vmbr0 with IPv4/CIDR 10.0.99.1/30):

Proxmox: Creating a new Linux bridge
Proxmox: Creating a new Linux bridge

Hint: I am using that bridge only for the purpose of securing my SSH port. No VM or LXC container will ever be attached to it.

Then edit the network configuration /etc/network/interfaces, add a iptables rule:

auto vmbr99
iface vmbr99 inet static
        address 10.0.99.1/30
        bridge-ports none
        bridge-stp off
        bridge-fd 0
        # General IP forwarding 
        echo 1 > /proc/sys/net/ipv4/ip_forward
        # Enable destination NATting from incoming addresses on port 10022 to localhost on port 22
        post-up         iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 10022 -j DNAT --to-destination 10.0.99.1:22
        post-down       iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 10022 -j DNAT --to-destination 10.0.99.1:22

Apply the network changes:

$ sudo cp /etc/network/interfaces /etc/network/interfaces.new
$ sudo systemctl restart networking.service

Thats it. Much more pretty than the first flavour, isn’t it? The rule is nearly the same as above so I think there is no need for further explaination.

Final steps

Check if you are able to connect to the Proxmox host via SSH on port 10022. If that works go on and turn on the cluster firewall of Proxmox:

Software Versions used

  • Proxmox: 7.1

Leave a Comment