Banner

Securing proxmox with nginx as reverse proxy, basic authentication, iptables and working vnc

Share it:
There are a some good tutorials for this topic out there, but they are either incomplete or are missing some point on how to configure nginx properly to work as a (reverse-) proxy with vnc etc.
I assume you have proxmox installed and running on port 8006. Note that some browsers have problems with https / ssl on non-standard ports, so think about using Firefox for testing your configuration.
First but optional is to instruct proxmox to only listen to connection from localhost. Therefore, create a file /etc/default/pveproxy:
1
sudo vim /etc/default/pveproxy
and insert
1
2
3
ALLOW_FROM="127.0.0.1"
DENY_FROM="all"
POLICY="allow"
Now proxmox only serves request from localhost.
In a next step, a reverse proxy is installed and configured using nginx. It is sufficient to install the light version of nginx for this task:
1
sudo aptitude install nginx-light
Now remove the link of the default nginx configuration and create your own reverse proxy configuration for proxmox that further redirects http to https:
1
2
sudo rm /etc/nginx/sites-enabled/default
sudo vim /etc/nginx/sites-enabled/proxmox
Copy the following lines into the file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
server {
        listen 80;
        server_name _;
        return 301 https://$hostname$request_uri;
}
server {
        listen 6008 ssl; #choose your port or just use 443
        server_name _; #place your domain or ip here if needed
        root /usr/share/nginx/www;
        ssl_certificate /etc/nginx/ssl/proxmox.crt;
        ssl_certificate_key /etc/nginx/ssl/proxmox.key;
        proxy_redirect off;
        location ~ ^.+websocket$ {
                proxy_pass https://127.0.0.1:8006;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
        }
        location / {
                proxy_pass https://127.0.0.1:8006;
        }
}
Most of the directives should be self-explaining. So let’s go through only some of them in detail:
  • proxy_redirect off: Do not replace upstream response-headers for HTTP/1.1 301 Moved Permanently
  • proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection “upgrade”: Websockets use hop by hop header (Upgrade), the proxy should forward them instead of dropping them (default and regular behavior). See nginx websocket documentation for more information. This directives are needed by the vnc console.
This is already a working configuration. Note: nginx runs in front of proxmox now. Therefore you certificate should be the certificate for your tld. If you have to create a certificate, see SAN Server Certificate.
Test your configuration by linking and activating the proxy:
1
2
sudo ln -s /etc/nginx/sites-available/pveproxy /etc/nginx/sites-enabled/
sudo service nginx restart
and open the site in the browser.
Now add basic authentication as another layer of security.
Open your nginx configuration:
1
sudo vim /etc/nginx/sites-available/pveproxy
Add the following lines before your location directives:
1
2
auth_basic "Login";
auth_basic_user_file /etc/nginx/.htpasswd;
This adds an basic authentication token before accessing the site. To generate the token, use openssl and type:
1
printf "${username}: `openssl passwd -apr1`\n" >> /etc/nginx/.htpasswd
You will be prompted for a password. Type in a password and open the token to add a user to it:
1
vim /etc/nginx/.htpasswd
You will see the hashed password. The username has to be added infront of the colon. Check that there is no space between the colon and the username and password. The token should have a structure like:
1
[your_username]:[hashed_password]
Restart nginx and check if everything is working as it mend to do.
Now lets face the firewall. I prefer using iptables directly instead of any iptable-wrapper. Here is a script in /etc/iptables/iptables.sh with basic rules that you can run as root.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#!/bin/bash
# Firewall Script
##################################################
##### Setting up default kernel tunings here #####
##################################################
#DROP ICMP echo-requests sent to broadcast/multi-cast addresses.
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
#DROP source routed packets
echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route
#Enable TCP SYN cookies
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
#Do not ACCEPT ICMP redirect
echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects
#Don't send ICMP redirect
echo 0 > /proc/sys/net/ipv4/conf/all/send_redirects
#Enable source spoofing protection
echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
#Log impossible (martian) packets
echo 1 > /proc/sys/net/ipv4/conf/all/log_martians
##################################################
# Flush all previous rules
##################################################
#Flush existing chains, you may add more here if you are using more chains
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -t raw -F
iptables -t raw -X
##################################################
#Setting up defaults etc
##################################################
EXT_IP="[your ip]"
DMZ="[your internal network e.g. 192.168.1.0/24]"
#Allow traffic on loopback
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
#Creating default policies
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP #If we're not a router
#Allow previously established connections
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
#Drop all packets with invalid headers or checksums
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
# Forward chain
iptables -A FORWARD -d $DMZ -j ACCEPT
iptables -A FORWARD -s $DMZ -j ACCEPT
###########################################################
#### Allow inbound connections on the ports we decided ####
###########################################################
iptables -A INPUT -p tcp --dport 80 -j ACCEPT -m comment --comment "Allow HTTP"
iptables -A INPUT -p tcp --dport 6008 -j ACCEPT -m comment --comment "Allow HTTPS"
iptables -A INPUT -p tcp --dport 443 -j ACCEPT -m comment --comment "Allow HTTPS"
iptables -A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT -m comment --comment "Allow SSH"
###########################################################
#### Allow outbound connections on the ports we decided ###
###########################################################
# System related
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT -m comment --comment "DNS"
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT -m comment --comment "DNS"
iptables -A OUTPUT -p udp --dport 67:68 -j ACCEPT -m comment --comment "DHCP"
iptables -A OUTPUT -p udp --dport 123 -j ACCEPT -m comment --comment "NTP"
# Email related
iptables -A OUTPUT -p tcp --dport 465 -j ACCEPT -m comment --comment "Allow SSL SMTP"
iptables -A OUTPUT -p tcp --dport 993 -j ACCEPT -m comment --comment "Allow SSL IMAP"
# VNC related
#iptables -A OUTPUT -p tcp --dport 5900:5999 -j ACCEPT -m comment --comment "Allow VNC"
#iptables -A INPUT -p tcp --dport 5900:5999 -j ACCEPT -m comment --comment "Allow VNC"
# Web access
iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT -m comment --comment "Allow HTTP"
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT -m comment --comment "Allow HTTPS"
# VM relatad
iptables -t nat -A POSTROUTING -s $DMZ -o [outgoing interface, e.g. eth0] -j SNAT --to-source $EXT_IP -m comment --comment "Nating"
###########################################################
# Allow bidirectional connections on the ports we decided #
###########################################################
# Allow ICMP ping incoming client request
iptables -A INPUT -p icmp --icmp-type echo-request -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow incoming pings"
iptables -A OUTPUT -p icmp --icmp-type echo-reply -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow incoming pings"
# Allow outgoing ping request
iptables -A OUTPUT -p icmp --icmp-type echo-request -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow outgoing pings"
iptables -A INPUT -p icmp --icmp-type echo-reply -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow outgoing pings"
#Set up logging for incoming traffic. Just comment out the following lines
#iptables -N LOGNDROP
#iptables -A INPUT -j LOGNDROP
#iptables -A LOGNDROP -j LOG
#iptables -A LOGNDROP -m limit --limit 2/min -j LOG --log-prefix "IPTables-Dropped: " --log-level 7
#iptables -A LOGNDROP -j DROP
#Save our firewall rules
iptables-save > /etc/iptables/iptables.up.rules
This blocks everything except the defined ports in the INPUT and OUTPUT chain.
Important note: The rules in the forward chain are necessary for the NAT process which happens in the POSTROUTING chain (SNAT)
To start these rules on machine boot, make the created rule-set executable and add a file /etc/network/if-pre-up.d/iptables. Add the following lines and make it executable, too.
1
2
#!/bin/sh
/sbin/iptables-restore < /etc/iptables/iptables.up.rules
If you are also using IPv6, you have to create another rule-set with ip6tables!
Further security measures:
  • Use fail2ban
  • Use rootkit hunter or a similar tool
  • Use TCP-Wrapper (/etc/hosts.deny any /etc/hosts.allow)
Have fun with your reasonable safe server ðŸ™‚
Share it:

Post A Comment:

0 comments: