├── .gitignore ├── roles └── iptables-docker │ ├── vars │ └── .placeholder │ ├── handlers │ └── main.yml │ ├── defaults │ └── main.yml │ ├── files │ ├── iptables-docker.service │ └── awk.firewall │ ├── tasks │ ├── main.yml │ ├── iptables-legacy.yml │ ├── uninstall.yml │ └── install.yml │ └── templates │ └── iptables-docker.sh.j2 ├── site.yml ├── src ├── iptables-docker.service ├── awk.firewall └── iptables-docker.sh ├── group_vars └── all.yml ├── uninstall.sh ├── install.sh ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | *.ini 2 | -------------------------------------------------------------------------------- /roles/iptables-docker/vars/.placeholder: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /site.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | remote_user: "ubuntu" # <- change this with your user 4 | become: yes 5 | roles: 6 | - role: roles/iptables-docker -------------------------------------------------------------------------------- /roles/iptables-docker/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: reload iptables-docker 3 | service: 4 | name: iptables-docker 5 | state: restarted 6 | enabled: yes -------------------------------------------------------------------------------- /roles/iptables-docker/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | docker_preserve: yes 3 | swarm_enabled: no 4 | ebable_icmp_messages: yes 5 | swarm_cidr: 192.168.1.0/24 6 | ssh_allow_cidr: 0.0.0.0/0 7 | iptables_allow_rules: [] 8 | iptables_docker_uninstall: no 9 | firewall_services: 10 | - ufw 11 | - firewalld -------------------------------------------------------------------------------- /src/iptables-docker.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Simple firewall script with docker rules preserve function 3 | After=network.target docker.service 4 | 5 | [Service] 6 | Type=oneshot 7 | RemainAfterExit=yes 8 | WorkingDirectory=/usr/local/sbin/ 9 | ExecStart=/usr/local/sbin/iptables-docker.sh start 10 | ExecStop=/usr/local/sbin/iptables-docker.sh stop 11 | 12 | [Install] 13 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /roles/iptables-docker/files/iptables-docker.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Simple firewall script with docker rules preserve function 3 | After=network.target docker.service 4 | 5 | [Service] 6 | Type=oneshot 7 | RemainAfterExit=yes 8 | WorkingDirectory=/usr/local/sbin/ 9 | ExecStart=/usr/local/sbin/iptables-docker.sh start 10 | ExecStop=/usr/local/sbin/iptables-docker.sh stop 11 | 12 | [Install] 13 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /group_vars/all.yml: -------------------------------------------------------------------------------- 1 | --- 2 | docker_preserve: yes 3 | swarm_enabled: no 4 | ebable_icmp_messages: yes 5 | swarm_cidr: 192.168.25.0/24 6 | ssh_allow_cidr: 0.0.0.0/0 7 | iptables_allow_rules: 8 | - desc: "Allow port 6466 tcp from 192.168.25.0/24" 9 | proto: tcp 10 | port: 6446 11 | from: 192.168.25.0/24 12 | - desc: "Allow port 8443 tcp from 192.168.25.0/24" 13 | proto: tcp 14 | port: 8443 15 | from: 192.168.25.0/24 -------------------------------------------------------------------------------- /uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Disable iptables-docker" 4 | 5 | systemctl stop iptables-docker 6 | systemctl disable iptables-docker 7 | 8 | echo "remove iptables-docker.sh" 9 | 10 | rm -rf /usr/local/sbin/iptables-docker.sh 11 | rm -rf /usr/local/sbin/awk.firewall 12 | 13 | echo "remove systemd unit" 14 | 15 | rm -rf /etc/systemd/system/iptables-docker.service 16 | 17 | echo "Reload systemd" 18 | 19 | systemctl daemon-reload -------------------------------------------------------------------------------- /roles/iptables-docker/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Populate service facts 3 | ansible.builtin.service_facts: 4 | 5 | - include_tasks: 6 | file: iptables-legacy.yml 7 | apply: 8 | tags: iptables-legacy,legacy 9 | tags: iptables-legacy,legacy 10 | 11 | - include_tasks: 12 | file: install.yml 13 | apply: 14 | tags: iptables-install,install 15 | tags: iptables-install,install 16 | when: iptables_docker_uninstall is false 17 | 18 | - include_tasks: 19 | file: uninstall.yml 20 | apply: 21 | tags: uninstall-install,uninstall 22 | tags: uninstall-install,uninstall 23 | when: iptables_docker_uninstall is true 24 | -------------------------------------------------------------------------------- /roles/iptables-docker/tasks/iptables-legacy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: check iptables version 3 | shell: iptables --version 4 | register: iptables_version 5 | changed_when: false 6 | 7 | - block: 8 | - alternatives: 9 | name: iptables 10 | path: /usr/sbin/iptables-legacy 11 | 12 | - alternatives: 13 | name: ip6tables 14 | path: /usr/sbin/ip6tables-legacy 15 | 16 | - reboot: 17 | msg: "Reboot initiated by Ansible for iptables-legacy" 18 | connect_timeout: 5 19 | reboot_timeout: 300 20 | pre_reboot_delay: 0 21 | post_reboot_delay: 30 22 | test_command: uptime 23 | when: '"nf_tables" in iptables_version.stdout' 24 | -------------------------------------------------------------------------------- /roles/iptables-docker/tasks/uninstall.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Enable firewall services 4 | service: 5 | name: "{{ item }}" 6 | state: started 7 | enabled: yes 8 | with_items: "{{ firewall_services }}" 9 | ignore_errors: yes 10 | 11 | - name: disable iptables-docker 12 | service: 13 | name: iptables-docker 14 | enabled: no 15 | state: stopped 16 | 17 | - name: remove iptables-docker.sh 18 | file: 19 | path: /usr/local/sbin/iptables-docker.sh 20 | state: absent 21 | 22 | - name: remove awk.firewall 23 | file: 24 | path: /usr/local/sbin/awk.firewall 25 | state: absent 26 | 27 | - name: remove iptables-docker.service 28 | file: 29 | path: /etc/systemd/system/iptables-docker.service 30 | state: absent 31 | 32 | - name: reload systemd 33 | systemd: 34 | daemon_reload: yes -------------------------------------------------------------------------------- /roles/iptables-docker/tasks/install.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Disable firewall services 4 | service: 5 | name: "{{ item }}" 6 | state: stopped 7 | enabled: no 8 | with_items: "{{ firewall_services }}" 9 | when: item in services 10 | 11 | - name: render iptables-docker.sh 12 | template: 13 | src: iptables-docker.sh.j2 14 | dest: /usr/local/sbin/iptables-docker.sh 15 | owner: root 16 | group: root 17 | mode: 0700 18 | notify: 19 | - reload iptables-docker 20 | 21 | - name: copy awk.firewall 22 | copy: 23 | src: awk.firewall 24 | dest: /usr/local/sbin/awk.firewall 25 | owner: root 26 | group: root 27 | mode: 0600 28 | notify: 29 | - reload iptables-docker 30 | 31 | - name: copy iptables-docker.service 32 | copy: 33 | src: iptables-docker.service 34 | dest: /etc/systemd/system/iptables-docker.service 35 | owner: root 36 | group: root 37 | mode: 0600 38 | 39 | - name: reload systemd 40 | systemd: 41 | daemon_reload: yes 42 | 43 | - name: enable iptables-docker 44 | service: 45 | name: iptables-docker 46 | enabled: yes 47 | state: started 48 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -o errexit 4 | set -o nounset 5 | if [ "${TRACE-0}" -eq 1 ]; then set -o xtrace; fi 6 | 7 | readonly SCRIPT_DIR=$(dirname -- "$0"); 8 | 9 | echo "Set iptables to iptables-legacy" 10 | 11 | iptables --version | grep legacy > /dev/null 12 | iptables_rc=$? 13 | if [ $iptables_rc -ne 0 ]; then 14 | update-alternatives --set iptables /usr/sbin/iptables-legacy 15 | update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy 16 | echo "You need to reboot your machine" 17 | fi 18 | 19 | echo "Disable ufw,firewalld" 20 | 21 | systemctl stop ufw 22 | systemctl disable ufw 23 | 24 | systemctl stop firewalld 25 | systemctl disable firewalld 26 | 27 | echo "Install iptables-docker.sh" 28 | 29 | cp "$SCRIPT_DIR/src/iptables-docker.sh" /usr/local/sbin/ 30 | cp "$SCRIPT_DIR/src/awk.firewall" /usr/local/sbin/ 31 | 32 | chmod 700 /usr/local/sbin/iptables-docker.sh 33 | chmod 600 /usr/local/sbin/awk.firewall 34 | 35 | echo "Create systemd unit" 36 | 37 | cp "$SCRIPT_DIR/src/iptables-docker.service" /etc/systemd/system/ 38 | 39 | echo "Enable iptables-docker.service" 40 | 41 | systemctl daemon-reload 42 | systemctl enable iptables-docker 43 | 44 | echo "start iptables-docker.service" 45 | 46 | systemctl start iptables-docker 47 | 48 | if [ $iptables_rc -ne 0 ]; then 49 | echo "Reboot your machine" 50 | fi -------------------------------------------------------------------------------- /src/awk.firewall: -------------------------------------------------------------------------------- 1 | { 2 | if ( $0 ~ /^*/ ) { 3 | in_nat=0 4 | in_filter=0 5 | } 6 | if ( $0 ~ /^*filter/ ) { 7 | in_filter=1 8 | in_nat=0 9 | print "*filter" 10 | print ":DOCKER-USER - [0:0]" 11 | print ":DOCKER - [0:0]" 12 | print ":DOCKER-INGRESS - [0:0]" 13 | print ":DOCKER-ISOLATION-STAGE-2 - [0:0]" 14 | print ":DOCKER-ISOLATION-STAGE-1 - [0:0]" 15 | print ":FORWARD DROP [0:0]" 16 | } 17 | if ( $0 ~ /^*nat/ ) { 18 | in_nat=1 19 | in_filter=0 20 | print "*nat" 21 | print ":PREROUTING ACCEPT [0:0]" 22 | print ":OUTPUT ACCEPT [0:0]" 23 | print ":POSTROUTING ACCEPT [0:0]" 24 | print ":DOCKER - [0:0]" 25 | print ":DOCKER-INGRESS - [0:0]" 26 | } 27 | if (in_nat==1) { 28 | if ($3 ~ /^(POSTROUTING|PREROUTING|DOCKER|DOCKER-INGRESS|OUTPUT)$/) {print $0} 29 | if ($0 ~ /^COMMIT/ ) {print "COMMIT"} 30 | } 31 | if (in_filter==1) { 32 | if ($3 ~ /^(DOCKER-ISOLATION-STAGE-1|DOCKER-ISOLATION-STAGE-2|DOCKER|DOCKER-INGRESS|DOCKER-USER)$/) { 33 | print $0 34 | } else { 35 | if ($7 ~ /^DOCKER$/) { 36 | bridge=$5 37 | print last_line 38 | } 39 | if (length(bridge) >0 && $5 == bridge) { 40 | print $0 41 | } 42 | } 43 | if ($0 ~ /^COMMIT/ ) {print "COMMIT"} 44 | } 45 | 46 | # remeber last line 47 | last_line=$0 48 | } 49 | -------------------------------------------------------------------------------- /roles/iptables-docker/files/awk.firewall: -------------------------------------------------------------------------------- 1 | { 2 | if ( $0 ~ /^*/ ) { 3 | in_nat=0 4 | in_filter=0 5 | } 6 | if ( $0 ~ /^*filter/ ) { 7 | in_filter=1 8 | in_nat=0 9 | print "*filter" 10 | print ":DOCKER-USER - [0:0]" 11 | print ":DOCKER - [0:0]" 12 | print ":DOCKER-INGRESS - [0:0]" 13 | print ":DOCKER-ISOLATION-STAGE-2 - [0:0]" 14 | print ":DOCKER-ISOLATION-STAGE-1 - [0:0]" 15 | print ":FORWARD DROP [0:0]" 16 | } 17 | if ( $0 ~ /^*nat/ ) { 18 | in_nat=1 19 | in_filter=0 20 | print "*nat" 21 | print ":PREROUTING ACCEPT [0:0]" 22 | print ":OUTPUT ACCEPT [0:0]" 23 | print ":POSTROUTING ACCEPT [0:0]" 24 | print ":DOCKER - [0:0]" 25 | print ":DOCKER-INGRESS - [0:0]" 26 | } 27 | if (in_nat==1) { 28 | if ($3 ~ /^(POSTROUTING|PREROUTING|DOCKER|DOCKER-INGRESS|OUTPUT)$/) {print $0} 29 | if ($0 ~ /^COMMIT/ ) {print "COMMIT"} 30 | } 31 | if (in_filter==1) { 32 | if ($3 ~ /^(DOCKER-ISOLATION-STAGE-1|DOCKER-ISOLATION-STAGE-2|DOCKER|DOCKER-INGRESS|DOCKER-USER)$/) { 33 | print $0 34 | } else { 35 | if ($7 ~ /^DOCKER$/) { 36 | bridge=$5 37 | print last_line 38 | } 39 | if (length(bridge) >0 && $5 == bridge) { 40 | print $0 41 | } 42 | } 43 | if ($0 ~ /^COMMIT/ ) {print "COMMIT"} 44 | } 45 | 46 | # remeber last line 47 | last_line=$0 48 | } 49 | -------------------------------------------------------------------------------- /src/iptables-docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -o errexit 4 | set -o nounset 5 | if [ "${TRACE-0}" -eq 1 ]; then set -o xtrace; fi 6 | 7 | cd "$(dirname "$0")" || exit 1 8 | 9 | dir=$(pwd) 10 | 11 | IPT=$(which iptables) 12 | 13 | interface=$(ip route | grep default | sed -e "s/^.*dev.//" -e "s/.proto.*//") 14 | 15 | readonly backup_dir_firwall_rules="/tmp/backup/firewall/" 16 | 17 | #### util functions 18 | 19 | beginswith() { case $2 in "$1"*) true;; *) false;; esac; } 20 | 21 | skip_docker_ifaces() { 22 | 23 | ## Skip all the interfaces created by docker: 24 | ## vethXXXXXX 25 | ## docker0 26 | ## docker_gwbridge 27 | ## br-XXXXXXXXXXX 28 | 29 | ifaces=$(ip -o link show | awk -F': ' '{print $2}') 30 | 31 | for i in $ifaces 32 | do 33 | if beginswith vet "$i"; then 34 | vet_value=${i%%@*} 35 | echo "Allow traffic on vet iface: $vet_value" 36 | $IPT -A INPUT -i "$vet_value" -j ACCEPT 37 | $IPT -A OUTPUT -o "$vet_value" -j ACCEPT 38 | fi 39 | if beginswith br- "$i"; then 40 | echo "Allow traffic on br- iface: $i" 41 | $IPT -A INPUT -i "$i" -j ACCEPT 42 | $IPT -A OUTPUT -o "$i" -j ACCEPT 43 | fi 44 | if beginswith docker "$i"; then 45 | echo "Allow traffic on docker iface: $i" 46 | $IPT -A INPUT -i "$i" -j ACCEPT 47 | $IPT -A OUTPUT -o "$i" -j ACCEPT 48 | fi 49 | done 50 | } 51 | 52 | #### end util functions 53 | 54 | start() { 55 | echo "############ ##############" 56 | 57 | mkdir -p "$backup_dir_firwall_rules" 58 | IPTABLES_SAVE_FILE="$backup_dir_firwall_rules/rules_$(date +%Y%m%d%H%M%S%N)" 59 | 60 | touch "$IPTABLES_SAVE_FILE" 61 | chmod 600 "$IPTABLES_SAVE_FILE" 62 | iptables-save -c >"$IPTABLES_SAVE_FILE" 63 | 64 | # flush all rules 65 | $IPT -F 66 | $IPT -X 67 | $IPT -Z 68 | $IPT -t filter --flush 69 | $IPT -t nat --flush 70 | $IPT -t mangle --flush 71 | 72 | # Preserve docker rules 73 | docker_restore 74 | 75 | # Skip filter on docker ifaces 76 | skip_docker_ifaces 77 | 78 | ### BLOCK INPUT BY DEFAULT ALLOW OUTPUT ### 79 | $IPT -P INPUT DROP 80 | $IPT -P OUTPUT ACCEPT 81 | 82 | # Enable free use of loopback interfaces 83 | $IPT -A INPUT -i lo -j ACCEPT 84 | $IPT -A OUTPUT -o lo -j ACCEPT 85 | 86 | ############### 87 | ### INPUT ### 88 | ############### 89 | 90 | # === anti scan === 91 | $IPT -N SCANS 92 | $IPT -A SCANS -p tcp --tcp-flags FIN,URG,PSH FIN,URG,PSH -j DROP 93 | $IPT -A SCANS -p tcp --tcp-flags ALL ALL -j DROP 94 | $IPT -A SCANS -p tcp --tcp-flags ALL NONE -j DROP 95 | $IPT -A SCANS -p tcp --tcp-flags SYN,RST SYN,RST -j DROP 96 | #################### 97 | echo "[Anti-scan is ready]" 98 | 99 | #No spoofing 100 | if [ -e /proc/sys/net/ipv4/conf/all/ip_filter ]; then 101 | for filtre in /proc/sys/net/ipv4/conf/*/rp_filter 102 | do 103 | echo > 1 "$filtre" 104 | done 105 | fi 106 | echo "[Anti-spoofing is ready]" 107 | 108 | #No synflood 109 | if [ -e /proc/sys/net/ipv4/tcp_syncookies ]; then 110 | echo 1 > /proc/sys/net/ipv4/tcp_syncookies 111 | fi 112 | echo "[Anti-synflood is ready]" 113 | 114 | #################### 115 | # === Clean particulars packets === 116 | #Make sure NEW incoming tcp connections are SYN packets 117 | $IPT -A INPUT -p tcp ! --syn -m state --state NEW -j DROP 118 | # Packets with incoming fragments 119 | $IPT -A INPUT -f -j DROP 120 | # incoming malformed XMAS packets 121 | $IPT -A INPUT -p tcp --tcp-flags ALL ALL -j DROP 122 | # Incoming malformed NULL packets 123 | $IPT -A INPUT -p tcp --tcp-flags ALL NONE -j DROP 124 | 125 | #Drop broadcast 126 | $IPT -A INPUT -m pkttype --pkt-type broadcast -j DROP 127 | 128 | # Accept inbound TCP packets 129 | $IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 130 | $IPT -A INPUT -p tcp --dport 22 -m state --state NEW -s 0.0.0.0/0 -j ACCEPT 131 | 132 | # Other firewall rules 133 | # insert here your firewall rules 134 | 135 | # Swarm mode - uncomment to enable swarm access (adjust source lan) 136 | # $IPT -A INPUT -p tcp --dport 2377 -m state --state NEW -s 192.168.1.0/24 -j ACCEPT 137 | # $IPT -A INPUT -p tcp --dport 7946 -m state --state NEW -s 192.168.1.0/24 -j ACCEPT 138 | # $IPT -A INPUT -p udp --dport 7946 -m state --state NEW -s 192.168.1.0/24 -j ACCEPT 139 | # $IPT -A INPUT -p udp --dport 4789 -m state --state NEW -s 192.168.1.0/24 -j ACCEPT 140 | 141 | # Accept inbound ICMP messages 142 | $IPT -A INPUT -p ICMP --icmp-type 8 -s 0.0.0.0/0 -j ACCEPT 143 | $IPT -A INPUT -p ICMP --icmp-type 11 -s 0.0.0.0/0 -j ACCEPT 144 | 145 | ############### 146 | ### LOG ### 147 | ############### 148 | 149 | $IPT -N LOGGING 150 | $IPT -A INPUT -j LOGGING 151 | $IPT -A LOGGING -m limit --limit 2/min -j LOG --log-prefix "IPTables-Dropped: " --log-level 4 152 | $IPT -A LOGGING -j DROP 153 | } 154 | 155 | docker_restore() { 156 | awk -f "$dir/awk.firewall" <"$IPTABLES_SAVE_FILE" | iptables-restore 157 | } 158 | 159 | stop() { 160 | ### OPEN ALL !!! ### 161 | echo "############ ##############" 162 | 163 | mkdir -p "$backup_dir_firwall_rules" 164 | IPTABLES_SAVE_FILE="$backup_dir_firwall_rules/rules_$(date +%Y%m%d%H%M%S%N)" 165 | 166 | touch "$IPTABLES_SAVE_FILE" 167 | chmod 600 "$IPTABLES_SAVE_FILE" 168 | iptables-save -c >"$IPTABLES_SAVE_FILE" 169 | 170 | # set the default policy to ACCEPT 171 | $IPT --policy INPUT ACCEPT 172 | $IPT --policy OUTPUT ACCEPT 173 | $IPT --policy FORWARD ACCEPT 174 | 175 | $IPT --flush 176 | $IPT -t nat --flush 177 | $IPT -t mangle --flush 178 | 179 | # Preserve docker rules 180 | docker_restore 181 | } 182 | 183 | case "$1" in 184 | start) 185 | start 186 | ;; 187 | stop) 188 | stop 189 | ;; 190 | restart) 191 | stop 192 | start 193 | ;; 194 | *) 195 | echo "systemctl {start|stop} iptables-docker.service" >&2 196 | echo "or" >&2 197 | echo "iptables-docker.sh {start|stop}" >&2 198 | exit 1 199 | ;; 200 | esac 201 | 202 | exit 0 203 | -------------------------------------------------------------------------------- /roles/iptables-docker/templates/iptables-docker.sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -o errexit 4 | set -o nounset 5 | if [ "${TRACE-0}" -eq 1 ]; then set -o xtrace; fi 6 | 7 | cd "$(dirname "$0")" || exit 1 8 | 9 | dir=$(pwd) 10 | 11 | IPT=$(which iptables) 12 | 13 | interface=$(ip route | grep default | sed -e "s/^.*dev.//" -e "s/.proto.*//") 14 | 15 | readonly backup_dir_firwall_rules="/tmp/backup/firewall/" 16 | 17 | #### util functions 18 | 19 | beginswith() { case $2 in "$1"*) true;; *) false;; esac; } 20 | 21 | skip_docker_ifaces() { 22 | 23 | ## Skip all the interfaces created by docker: 24 | ## vethXXXXXX 25 | ## docker0 26 | ## docker_gwbridge 27 | ## br-XXXXXXXXXXX 28 | 29 | ifaces=$(ip -o link show | awk -F': ' '{print $2}') 30 | 31 | for i in $ifaces 32 | do 33 | if beginswith vet "$i"; then 34 | vet_value=${i%%@*} 35 | echo "Allow traffic on vet iface: $vet_value" 36 | $IPT -A INPUT -i "$vet_value" -j ACCEPT 37 | $IPT -A OUTPUT -o "$vet_value" -j ACCEPT 38 | fi 39 | if beginswith br- "$i"; then 40 | echo "Allow traffic on br- iface: $i" 41 | $IPT -A INPUT -i "$i" -j ACCEPT 42 | $IPT -A OUTPUT -o "$i" -j ACCEPT 43 | fi 44 | if beginswith docker "$i"; then 45 | echo "Allow traffic on docker iface: $i" 46 | $IPT -A INPUT -i "$i" -j ACCEPT 47 | $IPT -A OUTPUT -o "$i" -j ACCEPT 48 | fi 49 | done 50 | } 51 | 52 | #### end util functions 53 | 54 | start() { 55 | echo "############ ##############" 56 | 57 | mkdir -p "$backup_dir_firwall_rules" 58 | IPTABLES_SAVE_FILE="$backup_dir_firwall_rules/rules_$(date +%Y%m%d%H%M%S%N)" 59 | 60 | touch "$IPTABLES_SAVE_FILE" 61 | chmod 600 "$IPTABLES_SAVE_FILE" 62 | iptables-save -c >"$IPTABLES_SAVE_FILE" 63 | 64 | # flush all rules 65 | $IPT -F 66 | $IPT -X 67 | $IPT -Z 68 | $IPT -t filter --flush 69 | $IPT -t nat --flush 70 | $IPT -t mangle --flush 71 | 72 | {% if docker_preserve|default(true) -%} 73 | # Preserve docker rules 74 | docker_restore 75 | 76 | # Skip filter on docker ifaces 77 | skip_docker_ifaces 78 | {% endif %} 79 | 80 | ### BLOCK INPUT BY DEFAULT ALLOW OUTPUT ### 81 | $IPT -P INPUT DROP 82 | $IPT -P OUTPUT ACCEPT 83 | 84 | # Enable free use of loopback interfaces 85 | $IPT -A INPUT -i lo -j ACCEPT 86 | $IPT -A OUTPUT -o lo -j ACCEPT 87 | 88 | ############### 89 | ### INPUT ### 90 | ############### 91 | 92 | # === anti scan === 93 | $IPT -N SCANS 94 | $IPT -A SCANS -p tcp --tcp-flags FIN,URG,PSH FIN,URG,PSH -j DROP 95 | $IPT -A SCANS -p tcp --tcp-flags ALL ALL -j DROP 96 | $IPT -A SCANS -p tcp --tcp-flags ALL NONE -j DROP 97 | $IPT -A SCANS -p tcp --tcp-flags SYN,RST SYN,RST -j DROP 98 | #################### 99 | echo "[Anti-scan is ready]" 100 | 101 | #No spoofing 102 | if [ -e /proc/sys/net/ipv4/conf/all/ip_filter ]; then 103 | for filtre in /proc/sys/net/ipv4/conf/*/rp_filter 104 | do 105 | echo > 1 "$filtre" 106 | done 107 | fi 108 | echo "[Anti-spoofing is ready]" 109 | 110 | #No synflood 111 | if [ -e /proc/sys/net/ipv4/tcp_syncookies ]; then 112 | echo 1 > /proc/sys/net/ipv4/tcp_syncookies 113 | fi 114 | echo "[Anti-synflood is ready]" 115 | 116 | #################### 117 | # === Clean particulars packets === 118 | #Make sure NEW incoming tcp connections are SYN packets 119 | $IPT -A INPUT -p tcp ! --syn -m state --state NEW -j DROP 120 | # Packets with incoming fragments 121 | $IPT -A INPUT -f -j DROP 122 | # incoming malformed XMAS packets 123 | $IPT -A INPUT -p tcp --tcp-flags ALL ALL -j DROP 124 | # Incoming malformed NULL packets 125 | $IPT -A INPUT -p tcp --tcp-flags ALL NONE -j DROP 126 | 127 | #Drop broadcast 128 | $IPT -A INPUT -m pkttype --pkt-type broadcast -j DROP 129 | 130 | # Accept inbound TCP packets 131 | $IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 132 | $IPT -A INPUT -p tcp --dport 22 -m state --state NEW -s {{ ssh_allow_cidr|default('0.0.0.0/0') }} -j ACCEPT 133 | 134 | {% if iptables_allow_rules|length > 0 -%} 135 | # Other firewall rules 136 | {% for iptables_rule in iptables_allow_rules -%} 137 | $IPT -A INPUT -p {{ iptables_rule.proto }} --dport {{ iptables_rule.port }} -m state --state NEW -s {{ iptables_rule.from|default('0.0.0.0/0') }} -j ACCEPT -m comment --comment "{{ iptables_rule.desc }}" 138 | {% endfor %} 139 | {% endif %} 140 | 141 | {% if swarm_enabled|default(false) -%} 142 | # Swarm mode 143 | $IPT -A INPUT -p tcp --dport 2377 -m state --state NEW -s {{ swarm_cidr|default('0.0.0.0/0') }} -j ACCEPT 144 | $IPT -A INPUT -p tcp --dport 7946 -m state --state NEW -s {{ swarm_cidr|default('0.0.0.0/0') }} -j ACCEPT 145 | $IPT -A INPUT -p udp --dport 7946 -m state --state NEW -s {{ swarm_cidr|default('0.0.0.0/0') }} -j ACCEPT 146 | $IPT -A INPUT -p udp --dport 4789 -m state --state NEW -s {{ swarm_cidr|default('0.0.0.0/0') }} -j ACCEPT 147 | {% endif %} 148 | 149 | {% if ebable_icmp_messages|default(true) -%} 150 | # Accept inbound ICMP messages 151 | $IPT -A INPUT -p ICMP --icmp-type 8 -s 0.0.0.0/0 -j ACCEPT 152 | $IPT -A INPUT -p ICMP --icmp-type 11 -s 0.0.0.0/0 -j ACCEPT 153 | {% endif %} 154 | 155 | ############### 156 | ### LOG ### 157 | ############### 158 | 159 | $IPT -N LOGGING 160 | $IPT -A INPUT -j LOGGING 161 | $IPT -A LOGGING -m limit --limit 2/min -j LOG --log-prefix "IPTables-Dropped: " --log-level 4 162 | $IPT -A LOGGING -j DROP 163 | } 164 | 165 | docker_restore() { 166 | awk -f "$dir/awk.firewall" <"$IPTABLES_SAVE_FILE" | iptables-restore 167 | } 168 | 169 | stop() { 170 | ### OPEN ALL !!! ### 171 | echo "############ ##############" 172 | 173 | mkdir -p "$backup_dir_firwall_rules" 174 | IPTABLES_SAVE_FILE="$backup_dir_firwall_rules/rules_$(date +%Y%m%d%H%M%S%N)" 175 | 176 | touch "$IPTABLES_SAVE_FILE" 177 | chmod 600 "$IPTABLES_SAVE_FILE" 178 | iptables-save -c >"$IPTABLES_SAVE_FILE" 179 | 180 | # set the default policy to ACCEPT 181 | $IPT --policy INPUT ACCEPT 182 | $IPT --policy OUTPUT ACCEPT 183 | $IPT --policy FORWARD ACCEPT 184 | 185 | $IPT --flush 186 | $IPT -t nat --flush 187 | $IPT -t mangle --flush 188 | 189 | {% if docker_preserve|default(true) -%} 190 | # Preserve docker rules 191 | docker_restore 192 | {% endif %} 193 | 194 | } 195 | 196 | case "$1" in 197 | start) 198 | start 199 | ;; 200 | stop) 201 | stop 202 | ;; 203 | restart) 204 | stop 205 | start 206 | ;; 207 | *) 208 | echo "systemctl {start|stop} iptables-docker.service" >&2 209 | echo "or" >&2 210 | echo "iptables-docker.sh {start|stop}" >&2 211 | exit 1 212 | ;; 213 | esac 214 | 215 | exit 0 216 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iptables-docker 2 | 3 | [![GitHub forks](https://img.shields.io/github/forks/garutilorenzo/iptables-docker)](https://github.com/garutilorenzo/iptables-docker/network) 4 | [![GitHub stars](https://img.shields.io/github/stars/garutilorenzo/iptables-docker)](https://github.com/garutilorenzo/iptables-docker/stargazers) 5 | ![GitHub](https://img.shields.io/github/license/garutilorenzo/iptables-docker) 6 | [![GitHub issues](https://img.shields.io/github/issues/garutilorenzo/iptables-docker)](https://github.com/garutilorenzo/iptables-docker/issues) 7 | 8 | ### A bash solution for docker and iptables conflict 9 | 10 | If you’ve ever tried to setup firewall rules on the same machine where docker daemon is running you may have noticed that docker (by default) manipulate your iptables chains. 11 | If you want the full control of your iptables rules this might be a problem. 12 | 13 | Before you proceed read carefully the [important notes](#important-notes) section. 14 | 15 | ### Table of Contents 16 | 17 | * [Docker and iptables](#docker-and-iptables) 18 | * [The problem](#the-problem) 19 | * [The solution](#the-solution) 20 | * [Usage](#usage) 21 | * [Test](#test-iptables-docker) 22 | * [Notes](#important-notes) 23 | * [Extending iptables-docker](#extending-iptables-docker) 24 | 25 | ### Docker and iptables 26 | 27 | Docker is utilizing the iptables "nat" to resolve packets from and to its containers and "filter" for isolation purposes, by default docker creates some chains in your iptables setup: 28 | 29 | ``` 30 | sudo iptables -L 31 | 32 | Chain INPUT (policy ACCEPT) 33 | target prot opt source destination 34 | 35 | Chain FORWARD (policy DROP) 36 | target prot opt source destination 37 | DOCKER-USER all -- anywhere anywhere 38 | DOCKER-ISOLATION-STAGE-1 all -- anywhere anywhere 39 | ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED 40 | DOCKER all -- anywhere anywhere 41 | ACCEPT all -- anywhere anywhere 42 | ACCEPT all -- anywhere anywhere 43 | 44 | Chain OUTPUT (policy ACCEPT) 45 | target prot opt source destination 46 | 47 | Chain DOCKER (1 references) 48 | target prot opt source destination 49 | 50 | Chain DOCKER-INGRESS (0 references) 51 | target prot opt source destination 52 | 53 | Chain DOCKER-ISOLATION-STAGE-1 (1 references) 54 | target prot opt source destination 55 | DOCKER-ISOLATION-STAGE-2 all -- anywhere anywhere 56 | RETURN all -- anywhere anywhere 57 | 58 | Chain DOCKER-ISOLATION-STAGE-2 (1 references) 59 | target prot opt source destination 60 | DROP all -- anywhere anywhere 61 | RETURN all -- anywhere anywhere 62 | 63 | Chain DOCKER-USER (1 references) 64 | target prot opt source destination 65 | RETURN all -- anywhere anywhere 66 | ``` 67 | 68 | now for example we have the need to expose our nginx container to the world: 69 | 70 | ``` 71 | docker run --name some-nginx -d -p 8080:80 nginx:latest 72 | 47a12adff13aa7609020a1aa0863b0dff192fbcf29507788a594e8b098ffe47a 73 | 74 | docker ps 75 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 76 | 47a12adff13a nginx:latest "/docker-entrypoint.…" 27 seconds ago Up 24 seconds 0.0.0.0:8080->80/tcp, :::8080->80/tcp some-nginx 77 | ``` 78 | 79 | and now we can reach our nginx default page: 80 | 81 | ``` 82 | curl -v http://192.168.25.200:8080 83 | 84 | * Trying 192.168.25.200:8080... 85 | * TCP_NODELAY set 86 | * Connected to 192.168.25.200 (192.168.25.200) port 8080 (#0) 87 | > GET / HTTP/1.1 88 | > Host: 192.168.25.200:8080 89 | > User-Agent: curl/7.68.0 90 | > Accept: */* 91 | > 92 | * Mark bundle as not supporting multiuse 93 | < HTTP/1.1 200 OK 94 | < Server: nginx/1.21.1 95 | < Date: Thu, 14 Oct 2021 10:31:38 GMT 96 | < Content-Type: text/html 97 | < Content-Length: 612 98 | < Last-Modified: Tue, 06 Jul 2021 14:59:17 GMT 99 | < Connection: keep-alive 100 | < ETag: "60e46fc5-264" 101 | < Accept-Ranges: bytes 102 | < 103 | 104 | 105 | 106 | Welcome to nginx! 107 |