Created
October 2, 2015 15:39
-
-
Save starkers/4a3f7c5b2557f1de3e93 to your computer and use it in GitHub Desktop.
A reasonably secure iptables stack to port forward to containers and isolate internal LANs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # I use this on servers hosting multiple containers. | |
| # It lets me reasonably easily manage ports without typing too much | |
| # Works on openvz and lxc... nothing really magical | |
| # Beware the spoof detection ranges.. if you expect legit traffic from one of these networks the modify it | |
| # There are a few bugs but generally this works well.. YMMV -david | |
| #public IP on my host (eth0) | |
| IP1=178.62.XX.XX | |
| #Additional IPs, typically aliased on eth0:X or assigned to a VM on venet0 | |
| IP2=178.62.XX.XY | |
| IP3=178.62.XX.XZ | |
| IP4=178.62.XX.YX | |
| #hint "ip a add 1.2.3.4/32 dev eth0:6" | |
| #We specify internal LANs for VMs, this will allow us to control their egress traffic later | |
| #IMPORTANT: export these as I'll want to parse variables called ^LAN* with env later on | |
| #sites and generally not so security concious VMs | |
| export LAN1=10.3.1.0/24 | |
| #blockchain stuffs | |
| export LAN2=10.3.2.0/24 | |
| #a friends | |
| export LAN3=10.3.3.0/24 | |
| #The physical device our host server has, typically eth0 | |
| HWNIC=eth0 | |
| #Path to iptables executable | |
| IPT=/sbin/iptables | |
| function : (){ | |
| #This function gets sent 4 variables | |
| # it will allow us to bind a VM to one of our public IPs | |
| ## Setup the DNAT | |
| $IPT -t nat -I PREROUTING -p tcp -d $IP_PUB --dport $PORT_PUB -j DNAT --to $IP_INT:$PORT_INT | |
| ## Allow it to forward | |
| $IPT -A FORWARD -p tcp -d $IP_PUB --dport $PORT_INT -j ACCEPT | |
| ## Allow the inbound | |
| $IPT -A INPUT -p tcp -d "$IP_PUB" --dport $PORT_PUB -j ACCEPT | |
| echo "+ $IP_PUB:$PORT_PUB -> $IP_INT:$PORT_INT" | |
| } | |
| function :udp (){ | |
| #This function gets sent 4 variables | |
| # it will allow us to bind a VM to one of our public IPs | |
| ## Setup the DNAT | |
| $IPT -t nat -I PREROUTING -p udp -d $IP_PUB --dport $PORT_PUB -j DNAT --to $IP_INT:$PORT_INT | |
| ## Allow it to forward | |
| $IPT -A FORWARD -p udp -d $IP_PUB --dport $PORT_INT -j ACCEPT | |
| ## Allow the inbound | |
| $IPT -A INPUT -p udp -d "$IP_PUB" --dport $PORT_PUB -j ACCEPT | |
| echo "+ $IP_PUB:$PORT_PUB -> $IP_INT:$PORT_INT" | |
| } | |
| function list (){ | |
| for policy in INPUT OUTPUT FORWARD ; do | |
| echo "------------------------START $policy CHAIN------------------------" | |
| $IPT -L "${policy}" -n --line-numbers | |
| echo "------------------------END $policy" ; echo | |
| done | |
| for chain in PREROUTING OUTPUT POSTROUTING ; do | |
| echo "------------------------START NAT chain: $policy ------------------------" | |
| $IPT -t nat -L "$chain" -n --line-numbers | |
| echo "------------------------END $policy" ; echo | |
| done | |
| } | |
| stop(){ | |
| echo "# stopping firewall entirely" | |
| $IPT -F | |
| $IPT -X | |
| $IPT -t nat -F | |
| $IPT -t nat -X | |
| $IPT -t mangle -F | |
| $IPT -t mangle -X | |
| $IPT -P INPUT ACCEPT | |
| $IPT -P FORWARD ACCEPT | |
| $IPT -P OUTPUT ACCEPT | |
| } | |
| start(){ | |
| echo "# starting firewall" | |
| for spoofed in \ | |
| 10.0.0.0/8 \ | |
| 172.16.0.0/12 \ | |
| 192.168.0.0/16 \ | |
| 244.0.0.0/4 \ | |
| 127.0.0.0/8 \ | |
| ; do | |
| echo "| blocking spoofed traffic on $HWNIC from $spoofed" # on $HWNIC" | |
| $IPT -A INPUT -i "$HWNIC" -s "$spoofed" -j LOG --log-prefix "IP_SPOOF: " | |
| $IPT -A INPUT -i "$HWNIC" -s "$spoofed" -j DROP | |
| done | |
| # echo "+ $BR_NET on $HWNIC" | |
| # $IPT -A INPUT -i "$HWNIC" -s "$BR_NET" -j ACCEPT | |
| # echo "+ ICMP PING responces only" | |
| # ### ** assumed that default INPUT policy set to DROP ** ############# | |
| # $IPT -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT | |
| # $IPT -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT | |
| # $IPT -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT | |
| # ## ** all our server to respond to pings ** ## | |
| # $IPT -A INPUT -p icmp --icmp-type echo-request -j ACCEPT | |
| echo "| setting INPUT policy to DROP" | |
| $IPT -P INPUT DROP | |
| echo "+ setting FORWARD policy to ACCEPT" | |
| $IPT -P FORWARD ACCEPT | |
| echo "+ setting OUTPUT policy to ACCEPT" | |
| $IPT -P OUTPUT ACCEPT | |
| ########## allow loopback ############# | |
| echo "+ global: I/O ACCEPT on lo" | |
| $IPT -A INPUT -i lo -j ACCEPT | |
| $IPT -A OUTPUT -o lo -j ACCEPT | |
| ########## Global allows ############# | |
| echo "+ global: accept *:22 on $HWNIC" | |
| $IPT -A INPUT -i "$HWNIC" -m tcp -p tcp --dport 22 -j ACCEPT | |
| echo "+ global: accept PING replies" | |
| $IPT -A INPUT -p icmp --icmp-type echo-request -j ACCEPT | |
| echo "+ allow established and related traffic (state based)" | |
| $IPT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT | |
| ########## LAN ISOLATION ############# | |
| # Here we ensure that $LAN1 cannot contact other internal LANS.. EG: $LAN2 or $LAN3 etc.. | |
| # | |
| # First lets asses if there is more than one $LAN[x] variable | |
| LAN_VARS="$(env | grep "^LAN[0-999]")" | |
| LAN_TOTAL="$(wc -l <<<"$LAN_VARS" )" | |
| if [ "$LAN_TOTAL" -gt 1 ]; then | |
| # if we have more than 1 $LAN[x] variable, isolate them from each other" | |
| function fwd_drop(){ | |
| echo "| blocking traffic between $1 and $2" | |
| $IPT -A FORWARD -s $1 -d $2 -j DROP | |
| } | |
| fwd_drop $LAN1 $LAN2 | |
| fwd_drop $LAN1 $LAN3 | |
| fwd_drop $LAN2 $LAN1 | |
| fwd_drop $LAN2 $LAN3 | |
| fwd_drop $LAN3 $LAN1 | |
| fwd_drop $LAN3 $LAN2 | |
| fi | |
| echo "# source NAT section" | |
| echo "/ nat postrouting enabled from $LAN1 - $IP1" | |
| $IPT -t nat -A POSTROUTING -s $LAN1 -o $HWNIC -j SNAT --to $IP1 | |
| echo "/ nat postrouting enabled from $LAN2 - $IP2" | |
| $IPT -t nat -A POSTROUTING -s $LAN2 -o $HWNIC -j SNAT --to $IP2 | |
| echo "/ nat postrouting enabled from $LAN3 - $IP3" | |
| $IPT -t nat -A POSTROUTING -s $LAN3 -o $HWNIC -j SNAT --to $IP3 | |
| # # Allow direct connections into our PRIMARY IP | |
| # echo "# public IP rules: $IP1" | |
| $IPT -A INPUT -p tcp --dport 80 -d $IP1 -j ACCEPT | |
| $IPT -A INPUT -p tcp --dport 443 -d $IP1 -j ACCEPT | |
| #OpenVZ Web panel | |
| $IPT -A INPUT -p tcp --dport 3030 -d $IP1 -j ACCEPT | |
| # # Route ports on our PRIMARY IP to VMs | |
| # IP_PUB="$IP1" IP_INT=10.3.1.1 PORT_PUB=2222 PORT_INT=22 : | |
| IP_PUB="$IP2" IP_INT=10.3.1.11 PORT_PUB=22 PORT_INT=22 : | |
| # IP_PUB="$IP3" IP_INT=10.3.0.65 PORT_PUB=22 PORT_INT=22 : | |
| # Route ports on our other IPs to other VMs | |
| echo "# public IP rules: $IP2 git.fcplm.net" | |
| IP_PUB="$IP2" IP_INT=10.3.7.5 PORT_PUB=22 PORT_INT=22 : | |
| IP_PUB="$IP2" IP_INT=10.3.7.5 PORT_PUB=80 PORT_INT=80 : | |
| IP_PUB="$IP2" IP_INT=10.3.7.5 PORT_PUB=443 PORT_INT=443 : | |
| # nzb: SABnzb | |
| IP_PUB="$IP2" IP_INT=10.3.1.5 PORT_PUB=31645 PORT_INT=9090 : | |
| # nzb: CouchPotato | |
| IP_PUB="$IP2" IP_INT=10.3.1.5 PORT_PUB=31646 PORT_INT=5050 : | |
| # nzb: Sickbeard | |
| IP_PUB="$IP2" IP_INT=10.3.1.5 PORT_PUB=31647 PORT_INT=8081 : | |
| # nzb: SSH | |
| IP_PUB="$IP2" IP_INT=10.3.1.5 PORT_PUB=31648 PORT_INT=22 : | |
| # syncthing | |
| IP_PUB="$IP1" IP_INT=10.3.2.4 PORT_PUB=80 PORT_INT=80 : #export of some stuff in http (htaccess) | |
| IP_PUB="$IP2" IP_INT=10.3.2.4 PORT_PUB=8080 PORT_INT=8080 : #syncthing https gui | |
| IP_PUB="$IP2" IP_INT=10.3.2.4 PORT_PUB=22000 PORT_INT=22000 : #syncthing egress | |
| IP_PUB="$IP2" IP_INT=10.3.2.4 PORT_PUB=11000 PORT_INT=8112 : #deluge | |
| #s media munch.digtux.com | |
| IP_PUB="$IP1" IP_INT=10.3.4.10 PORT_PUB=3200 PORT_INT=22 : #ssh | |
| IP_PUB="$IP1" IP_INT=10.3.4.10 PORT_PUB=3201 PORT_INT=8001 : #sab | |
| IP_PUB="$IP1" IP_INT=10.3.4.10 PORT_PUB=3202 PORT_INT=8002 : #sick | |
| # notes: rainy/tomboy notes (ssl) | |
| IP_PUB="$IP2" IP_INT=10.3.2.3 PORT_PUB=31641 PORT_INT=31641 : | |
| # misc: SSH in for unison and rsnapshot backups | |
| IP_PUB="$IP2" IP_INT=10.3.7.1 PORT_PUB=31422 PORT_INT=22 : | |
| #gollum | |
| # IP_PUB="$IP2" IP_INT=10.3.7.5 PORT_PUB=31351 PORT_INT=4000 : | |
| #Flaskwallet nginx | |
| IP_PUB="$IP2" IP_INT=10.3.2.2 PORT_PUB=7264 PORT_INT=7264 : | |
| #minecraft SSH | |
| IP_PUB="$IP5" IP_INT=10.3.1.21 PORT_PUB=22 PORT_INT=22 : | |
| #toms minecraft Daemon | |
| IP_PUB="$IP2" IP_INT=10.3.1.21 PORT_PUB=25565 PORT_INT=25565 : #legacy | |
| IP_PUB="$IP5" IP_INT=10.3.1.21 PORT_PUB=80 PORT_INT=80 : | |
| IP_PUB="$IP5" IP_INT=10.3.1.21 PORT_PUB=25565 PORT_INT=25565 : | |
| IP_PUB="$IP5" IP_INT=10.3.1.21 PORT_PUB=25566 PORT_INT=25566 : | |
| IP_PUB="$IP5" IP_INT=10.3.1.21 PORT_PUB=25567 PORT_INT=25567 : | |
| IP_PUB="$IP5" IP_INT=10.3.1.21 PORT_PUB=25568 PORT_INT=25568 : | |
| IP_PUB="$IP5" IP_INT=10.3.1.21 PORT_PUB=25569 PORT_INT=25569 : | |
| IP_PUB="$IP5" IP_INT=10.3.1.21 PORT_PUB=25570 PORT_INT=25570 : | |
| #mc1 mumble | |
| IP_PUB="$IP5" IP_INT=10.3.1.21 PORT_PUB=64738 PORT_INT=64738 : | |
| IP_PUB="$IP5" IP_INT=10.3.1.21 PORT_PUB=64738 PORT_INT=64738 :udp | |
| IP_PUB="$IP6" IP_INT=10.3.1.22 PORT_PUB=22 PORT_INT=22 : | |
| #alex minec6aft Daemon | |
| IP_PUB="$IP6" IP_INT=10.3.1.22 PORT_PUB=25565 PORT_INT=25565 : #legacy | |
| IP_PUB="$IP6" IP_INT=10.3.1.22 PORT_PUB=80 PORT_INT=80 : | |
| IP_PUB="$IP6" IP_INT=10.3.1.22 PORT_PUB=25565 PORT_INT=25565 : | |
| IP_PUB="$IP6" IP_INT=10.3.1.22 PORT_PUB=25566 PORT_INT=25566 : | |
| IP_PUB="$IP6" IP_INT=10.3.1.22 PORT_PUB=25567 PORT_INT=25567 : | |
| IP_PUB="$IP6" IP_INT=10.3.1.22 PORT_PUB=25568 PORT_INT=25568 : | |
| IP_PUB="$IP6" IP_INT=10.3.1.22 PORT_PUB=8123 PORT_INT=8123 : | |
| #AKA: some server | |
| IP_PUB="$IP7" IP_INT=10.3.7.7 PORT_PUB=22 PORT_INT=22 : | |
| IP_PUB="$IP7" IP_INT=10.3.7.7 PORT_PUB=80 PORT_INT=80 : | |
| IP_PUB="$IP7" IP_INT=10.3.7.7 PORT_PUB=443 PORT_INT=443 : | |
| IP_PUB="$IP7" IP_INT=10.3.7.7 PORT_PUB=25 PORT_INT=25 : #postfix | |
| IP_PUB="$IP7" IP_INT=10.3.7.7 PORT_PUB=587 PORT_INT=587 : #postfix | |
| IP_PUB="$IP7" IP_INT=10.3.7.7 PORT_PUB=993 PORT_INT=993 : #dovecot imaps | |
| IP_PUB="$IP7" IP_INT=10.3.7.7 PORT_PUB=2703 PORT_INT=2703 : #Razor2 | |
| IP_PUB="$IP7" IP_INT=10.3.7.7 PORT_PUB=24441 PORT_INT=24441 : #pyzor | |
| IP_PUB="$IP7" IP_INT=10.3.7.7 PORT_PUB=24441 PORT_INT=24441 :udp #pyzor | |
| # Ringos dns | |
| IP_PUB="$IP2" IP_INT=10.3.5.1 PORT_PUB=2028 PORT_INT=22 : | |
| IP_PUB="$IP2" IP_INT=10.3.5.1 PORT_PUB=2028 PORT_INT=2222 : | |
| IP_PUB="$IP2" IP_INT=10.3.5.1 PORT_PUB=3306 PORT_INT=3306 : | |
| IP_PUB="$IP2" IP_INT=10.3.5.1 PORT_PUB=4444 PORT_INT=4444 : | |
| IP_PUB="$IP2" IP_INT=10.3.5.1 PORT_PUB=4567 PORT_INT=4567 : | |
| IP_PUB="$IP2" IP_INT=10.3.5.1 PORT_PUB=4568 PORT_INT=4568 : | |
| IP_PUB="$IP2" IP_INT=10.3.5.1 PORT_PUB=53 PORT_INT=53 :udp | |
| # Johns SSH | |
| IP_PUB="$IP2" IP_INT=10.3.4.1 PORT_PUB=5122 PORT_INT=22 : | |
| # Proxy | |
| IP_PUB="$IP2" IP_INT=10.3.6.1 PORT_PUB=3128 PORT_INT=3128 : | |
| # mx1 | |
| IP_PUB="$IP2" IP_INT=10.3.1.3 PORT_PUB=80 PORT_INT=80 : | |
| IP_PUB="$IP2" IP_INT=10.3.1.3 PORT_PUB=443 PORT_INT=443 : | |
| #smtp, submission | |
| IP_PUB="$IP2" IP_INT=10.3.1.3 PORT_PUB=25 PORT_INT=25 : | |
| IP_PUB="$IP2" IP_INT=10.3.1.3 PORT_PUB=587 PORT_INT=587 : | |
| #imaps | |
| IP_PUB="$IP2" IP_INT=10.3.1.3 PORT_PUB=993 PORT_INT=993 : | |
| #pyzor (anti spam) | |
| IP_PUB="$IP2" IP_INT=10.3.1.3 PORT_PUB=24441 PORT_INT=24441 : | |
| # IP3 -"FLEXI" IP (g3) | |
| IP_PUB="$IP3" IP_INT=10.3.3.1 PORT_PUB=22 PORT_INT=22 : | |
| IP_PUB="$IP3" IP_INT=10.3.3.1 PORT_PUB=80 PORT_INT=80 : | |
| IP_PUB="$IP3" IP_INT=10.3.3.1 PORT_PUB=443 PORT_INT=443 : | |
| service fail2ban restart | |
| } | |
| case "$1" in | |
| start) | |
| start | |
| ;; | |
| stop) | |
| stop | |
| ;; | |
| status) | |
| iptables-save | |
| ;; | |
| restart) | |
| stop | |
| start | |
| ;; | |
| list) | |
| list | |
| ;; | |
| *) | |
| echo $"Usage: $0 {start|stop|restart|status|list}" | |
| exit 1 | |
| esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment