This is used for apps which are using OpenID to login but still need to be able to verify the users password or app password
202 lines
11 KiB
Bash
Executable File
202 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -eu -o pipefail
|
|
|
|
echo "==> Setting up firewall"
|
|
|
|
has_ipv6=$(cat /proc/net/if_inet6 >/dev/null 2>&1 && echo "yes" || echo "no")
|
|
|
|
# wait for 120 seconds for xtables lock, checking every 1 second
|
|
readonly iptables="iptables --wait 120"
|
|
readonly ip6tables="ip6tables --wait 120"
|
|
|
|
function ipxtables() {
|
|
$iptables "$@"
|
|
[[ "${has_ipv6}" == "yes" ]] && $ip6tables "$@"
|
|
}
|
|
|
|
ipxtables -t filter -N CLOUDRON || true
|
|
ipxtables -t filter -F CLOUDRON # empty any existing rules
|
|
|
|
# first setup any user IP block lists . remove all references in iptables before destroying them
|
|
echo "==> Creating ipset cloudron_blocklist"
|
|
$iptables -t filter -D DOCKER-USER -m set --match-set cloudron_blocklist src -j DROP || true
|
|
sleep 1 # without this there is a race that iptables is still referencing the ipset
|
|
ipset destroy cloudron_blocklist || true
|
|
ipset create cloudron_blocklist hash:net maxelem 262144 || true # if you change the size, change network.js size check
|
|
|
|
echo "==> Creating ipset cloudron_blocklist6"
|
|
$ip6tables -D FORWARD -m set --match-set cloudron_blocklist6 src -j DROP || true
|
|
sleep 1 # without this there is a race that iptables is still referencing the ipset
|
|
ipset destroy cloudron_blocklist6 || true
|
|
ipset create cloudron_blocklist6 hash:net family inet6 maxelem 262144 || true # if you change the size, change network.js size check
|
|
|
|
/home/yellowtent/box/src/scripts/setblocklist.sh
|
|
|
|
$iptables -t filter -A CLOUDRON -m set --match-set cloudron_blocklist src -j DROP
|
|
$iptables -t filter -I DOCKER-USER 1 -m set --match-set cloudron_blocklist src -j DROP # the DOCKER-USER chain is not cleared on docker restart
|
|
|
|
$ip6tables -t filter -A CLOUDRON -m set --match-set cloudron_blocklist6 src -j DROP
|
|
$ip6tables -I FORWARD 1 -m set --match-set cloudron_blocklist6 src -j DROP # there is no DOCKER-USER chain in ip6tables, bug?
|
|
|
|
# allow related and establisted connections
|
|
echo "==> Opening standard ports"
|
|
ipxtables -t filter -A CLOUDRON -m state --state RELATED,ESTABLISHED -j ACCEPT
|
|
ipxtables -t filter -A CLOUDRON -p tcp -m tcp -m multiport --dports 22,80,202,443 -j ACCEPT # 202 is the alternate ssh port
|
|
|
|
# whitelist any user ports. we used to use --dports but it has a 15 port limit (XT_MULTI_PORTS)
|
|
echo "==> Opening up user specified ports"
|
|
ports_json="/home/yellowtent/platformdata/firewall/ports.json"
|
|
if allowed_tcp_ports=$(node -e "console.log(JSON.parse(fs.readFileSync('${ports_json}', 'utf8')).allowed_tcp_ports.join(' '))" 2>/dev/null); then
|
|
for p in $allowed_tcp_ports; do
|
|
ipxtables -A CLOUDRON -p tcp -m tcp --dport "${p}" -j ACCEPT
|
|
done
|
|
fi
|
|
|
|
if allowed_udp_ports=$(node -e "console.log(JSON.parse(fs.readFileSync('${ports_json}', 'utf8')).allowed_udp_ports.join(' '))" 2>/dev/null); then
|
|
for p in $allowed_udp_ports; do
|
|
ipxtables -A CLOUDRON -p udp -m udp --dport "${p}" -j ACCEPT
|
|
done
|
|
fi
|
|
|
|
# LDAP user directory allow list
|
|
echo "==> Configuring LDAP allow list"
|
|
if ! ipset list cloudron_ldap_allowlist >/dev/null 2>&1; then
|
|
echo "==> Creating the cloudron_ldap_allowlist ipset"
|
|
ipset create cloudron_ldap_allowlist hash:net
|
|
fi
|
|
ipset flush cloudron_ldap_allowlist
|
|
|
|
if ! ipset list cloudron_ldap_allowlist6 >/dev/null 2>&1; then
|
|
echo "==> Creating the cloudron_ldap_allowlist6 ipset"
|
|
ipset create cloudron_ldap_allowlist6 hash:net family inet6
|
|
fi
|
|
ipset flush cloudron_ldap_allowlist6
|
|
|
|
ldap_allowlist="/home/yellowtent/platformdata/firewall/ldap_allowlist.txt"
|
|
# delete any existing redirect rule
|
|
$iptables -t nat -D PREROUTING -p tcp --dport 636 -j REDIRECT --to-ports 3004 2>/dev/null || true
|
|
$ip6tables -t nat -D PREROUTING -p tcp --dport 636 -j REDIRECT --to-ports 3004 >/dev/null || true
|
|
if [[ -f "${ldap_allowlist}" ]]; then
|
|
# without the -n block, any last line without a new line won't be read it!
|
|
while read -r line || [[ -n "$line" ]]; do
|
|
[[ -z "${line}" ]] && continue # ignore empty lines
|
|
[[ "$line" =~ ^#.*$ ]] && continue # ignore lines starting with #
|
|
if [[ "$line" == *":"* ]]; then
|
|
ipset add -! cloudron_ldap_allowlist6 "${line}" # the -! ignore duplicates
|
|
else
|
|
ipset add -! cloudron_ldap_allowlist "${line}" # the -! ignore duplicates
|
|
fi
|
|
done < "${ldap_allowlist}"
|
|
|
|
# ldap server we expose 3004 and also redirect from standard ldaps port 636
|
|
$iptables -t nat -I PREROUTING -p tcp --dport 636 -j REDIRECT --to-ports 3004
|
|
$iptables -t filter -A CLOUDRON -m set --match-set cloudron_ldap_allowlist src -p tcp --dport 3004 -j ACCEPT
|
|
|
|
$ip6tables -t nat -I PREROUTING -p tcp --dport 636 -j REDIRECT --to-ports 3004
|
|
$ip6tables -t filter -A CLOUDRON -m set --match-set cloudron_ldap_allowlist6 src -p tcp --dport 3004 -j ACCEPT
|
|
fi
|
|
|
|
# turn and stun service (constants.TURN_PORT, constants.TURN_TLS_PORT, constants.TURN_UDP_PORT_START, constants.TURN_UDP_PORT_END)
|
|
echo "==> Opening ports for TURN and STUN"
|
|
ipxtables -t filter -A CLOUDRON -p tcp -m multiport --dports 3478,5349 -j ACCEPT
|
|
ipxtables -t filter -A CLOUDRON -p udp -m multiport --dports 3478,5349 -j ACCEPT
|
|
ipxtables -t filter -A CLOUDRON -p udp -m multiport --dports 50000:50100 -j ACCEPT
|
|
|
|
# ICMPv6 is very fundamental to IPv6 connectivity unlike ICMPv4
|
|
echo "==> Allow ICMP"
|
|
$iptables -t filter -A CLOUDRON -p icmp --icmp-type echo-request -j ACCEPT
|
|
$iptables -t filter -A CLOUDRON -p icmp --icmp-type echo-reply -j ACCEPT
|
|
$ip6tables -t filter -A CLOUDRON -p ipv6-icmp -j ACCEPT
|
|
# NDP (546) and RA (547) portion of ICMPv6
|
|
$ip6tables -t filter -A CLOUDRON -p udp --sport 547 --dport 546 -j ACCEPT
|
|
|
|
ipxtables -t filter -A CLOUDRON -p udp --sport 53 -j ACCEPT
|
|
# for ldap,dockerproxy server (ipv4 only) to accept connections from apps. for connecting to addons and mail container ports, docker already has rules
|
|
$iptables -t filter -A CLOUDRON -p tcp -s 172.18.0.0/16 -d 172.18.0.1 -m multiport --dports 3002,3003,3006 -j ACCEPT
|
|
$iptables -t filter -A CLOUDRON -p udp -s 172.18.0.0/16 --dport 53 -j ACCEPT # dns responses from docker (127.0.0.11)
|
|
ipxtables -t filter -A CLOUDRON -i lo -j ACCEPT # required for localhost connections (mysql)
|
|
|
|
# log dropped incoming. keep this at the end of all the rules
|
|
ipxtables -t filter -A CLOUDRON -m limit --limit 2/min -j LOG --log-prefix "Packet dropped: " --log-level 7
|
|
ipxtables -t filter -A CLOUDRON -j DROP
|
|
|
|
# prepend our chain to the filter table
|
|
echo "==> Adding cloudron filter chain"
|
|
$iptables -t filter -C INPUT -j CLOUDRON 2>/dev/null || $iptables -t filter -I INPUT -j CLOUDRON
|
|
$ip6tables -t filter -C INPUT -j CLOUDRON 2>/dev/null || $ip6tables -t filter -I INPUT -j CLOUDRON
|
|
|
|
# masquerading rules for container ports to be accessible using public IP from other containers
|
|
echo "==> Adding cloudron postrouting chain"
|
|
ipxtables -t nat -N CLOUDRON_POSTROUTING || true
|
|
ipxtables -t nat -F CLOUDRON_POSTROUTING # empty any existing rules
|
|
|
|
$iptables -t nat -A CLOUDRON_POSTROUTING -s 172.18.0.0/16 -d 172.18.0.0/16 -j MASQUERADE
|
|
$ip6tables -t nat -A CLOUDRON_POSTROUTING -s fd00:c107:d509::/64 -d fd00:c107:d509::/64 -j MASQUERADE
|
|
|
|
$iptables -t nat -C POSTROUTING -j CLOUDRON_POSTROUTING 2>/dev/null || $iptables -t nat -I POSTROUTING -j CLOUDRON_POSTROUTING
|
|
$ip6tables -t nat -C POSTROUTING -j CLOUDRON_POSTROUTING 2>/dev/null || $ip6tables -t nat -I POSTROUTING -j CLOUDRON_POSTROUTING
|
|
|
|
# Setup rate limit chain (the recent info is at /proc/net/xt_recent)
|
|
echo "==> Setup rate limit chain"
|
|
ipxtables -t filter -N CLOUDRON_RATELIMIT || true
|
|
ipxtables -t filter -F CLOUDRON_RATELIMIT # empty any existing rules
|
|
|
|
# log dropped incoming. keep this at the end of all the rules
|
|
echo "==> Setup logging"
|
|
ipxtables -t filter -N CLOUDRON_RATELIMIT_LOG || true
|
|
ipxtables -t filter -F CLOUDRON_RATELIMIT_LOG # empty any existing rules
|
|
ipxtables -t filter -A CLOUDRON_RATELIMIT_LOG -m limit --limit 2/min -j LOG --log-prefix "IPTables RateLimit: " --log-level 7
|
|
ipxtables -t filter -A CLOUDRON_RATELIMIT_LOG -j DROP
|
|
|
|
# http https . 5000 requests per second per IP
|
|
for port in 80 443; do
|
|
ipxtables -A CLOUDRON_RATELIMIT -p tcp --syn --dport ${port} -m connlimit --connlimit-above 5000 -j CLOUDRON_RATELIMIT_LOG
|
|
done
|
|
|
|
# ssh and sftp. 5 connections per 10 seconds per IP
|
|
for port in 22 202 222; do
|
|
ipxtables -A CLOUDRON_RATELIMIT -p tcp --dport ${port} -m state --state NEW -m recent --set --name "public-${port}"
|
|
ipxtables -A CLOUDRON_RATELIMIT -p tcp --dport ${port} -m state --state NEW -m recent --update --name "public-${port}" --seconds 10 --hitcount 5 -j CLOUDRON_RATELIMIT_LOG
|
|
done
|
|
|
|
# ldaps
|
|
for port in 636 3004; do
|
|
ipxtables -A CLOUDRON_RATELIMIT -p tcp --syn --dport ${port} -m connlimit --connlimit-above 5000 -j CLOUDRON_RATELIMIT_LOG
|
|
done
|
|
|
|
# docker translates (dnat) 25, 587, 993, 4190 in the PREROUTING step . 50 connections per second per app
|
|
for port in 2525 4190 9993; do
|
|
$iptables -A CLOUDRON_RATELIMIT -p tcp --syn ! -s 172.18.0.0/16 -d 172.18.0.0/16 --dport ${port} -m connlimit --connlimit-above 50 -j CLOUDRON_RATELIMIT_LOG
|
|
done
|
|
|
|
# msa, ldap, imap, sieve, pop3 . 500 connections per second per app
|
|
for port in 2525 3002 4190 9993 9995; do
|
|
$iptables -A CLOUDRON_RATELIMIT -p tcp --syn -s 172.18.0.0/16 -d 172.18.0.0/16 --dport ${port} -m connlimit --connlimit-above 500 -j CLOUDRON_RATELIMIT_LOG
|
|
done
|
|
|
|
# cloudron docker network: mysql postgresql redis mongodb. 5000 connections per second per app
|
|
for port in 3306 5432 6379 27017; do
|
|
$iptables -A CLOUDRON_RATELIMIT -p tcp --syn -s 172.18.0.0/16 -d 172.18.0.0/16 --dport ${port} -m connlimit --connlimit-above 5000 -j CLOUDRON_RATELIMIT_LOG
|
|
done
|
|
|
|
# Add the rate limit chain to input chain
|
|
$iptables -t filter -C INPUT -j CLOUDRON_RATELIMIT 2>/dev/null || $iptables -t filter -I INPUT 1 -j CLOUDRON_RATELIMIT
|
|
$ip6tables -t filter -C INPUT -j CLOUDRON_RATELIMIT 2>/dev/null || $ip6tables -t filter -I INPUT 1 -j CLOUDRON_RATELIMIT
|
|
|
|
# Workaround issue where Docker insists on adding itself first in FORWARD table
|
|
ipxtables -D FORWARD -j CLOUDRON_RATELIMIT || true
|
|
ipxtables -I FORWARD 1 -j CLOUDRON_RATELIMIT
|
|
|
|
echo "==> Adding cloudron output chain"
|
|
ipxtables -t filter -N CLOUDRON_OUTPUT || true
|
|
ipxtables -t filter -F CLOUDRON_OUTPUT # empty any existing rules
|
|
|
|
# turn - mitigate reflection/amplification attack with UDP . The 5349 port is DTLS/UDP and not affected. https://github.com/coturn/coturn/pull/1588
|
|
# hashlimit-above is applied _after_ allowing a hashlimit-burst
|
|
sudo iptables -t filter -A CLOUDRON_OUTPUT -p udp --sport 3478 -m hashlimit --hashlimit-name turn-401 --hashlimit-above 10/second --hashlimit-burst 30 --hashlimit-mode dstip -j CLOUDRON_RATELIMIT_LOG
|
|
|
|
# Add the ouput rate limit chain to output chain
|
|
$iptables -t filter -C OUTPUT -j CLOUDRON_OUTPUT 2>/dev/null || $iptables -t filter -I OUTPUT 1 -j CLOUDRON_OUTPUT
|
|
$ip6tables -t filter -C INPUT -j CLOUDRON_OUTPUT 2>/dev/null || $ip6tables -t filter -I OUTPUT 1 -j CLOUDRON_OUTPUT
|