Ansible Galaxy role cesnet.firewall that installs iptables firewall on Debian prepared for rules for Docker.
The role creates a systemd service named "iptables" for applying rules and enables it for reboots. Apply rules from /etc/iptables with:
systemctl restart iptables
- firewall_do_install - installs iptables-legacy and selects them as the default iptables alternative
- firewall_do_config - creates files with rules and applies them
- firewall_open_ssh_ports - predefined rules for accepting ssh only from networks of MUNI,CESNET,ZCU
- firewall_open_tcp_ports - empty set, define as in the example below
- firewall_known_ranges - known ranges for the Czech academic network
- firewall_docker_rules - empty set, one rule per port can be defined for restricting access to Docker containers
- hosts: all
roles:
- role: cesnet.firewall
vars:
firewall_open_ssh_ports:
- { port: "ssh", ipv4: "147.251.0.0/16", comment: "accept ssh from MUNI" }
- { port: "ssh", ipv4: "147.228.0.0/16", comment: "accept ssh from ZCU" }
- { port: "ssh", ipv4: "147.231.0.0/16", comment: "accept ssh from CAS" }
- { port: "ssh", ipv4: "160.217.0.0/16", comment: "accept ssh from JCU" }
- { port: "ssh", ipv4: "78.128.208.0/20", comment: "accept ssh from CESNET" }
- { port: "ssh", ipv4: "195.113.0.0/16", comment: "accept ssh from CESNET" }
- { port: "ssh", ipv6: "2001:718::/32", comment: "accept ssh from CESNET provider" }
firewall_open_tcp_ports:
- { port: 25, ipv4: "147.251.0.0/16", comment: "accept SMTP from MUNI" }
- { port: 80, comment: "accept http" }
- { port: 443, comment: "accept https" }
- { port: 636, comment: "accept ldaps" }
- { port: 5432, ipv6: "2001:718::/32", comment: "accept postgres from CESNET" }
- { port: 5432, ipv6: "147.251.0.0/16", comment: "accept postgres from MUNI" }
- { port: 9000, ipv6: "2001:718:801::/48", comment: "accept portainer from MUNI" }
firewall_docker_rules:
- port: 9000
only:
- { ipv4: "147.251.0.0/16", comment: "portainer from MUNI"}
- { ipv4: "78.128.246.160/32", comment: "portainer from CESNET eduVPN" }
- { ipv4: "78.128.247.175/32", comment: "portainer from CESNET eduVPN" }
- port: 443
only:
- { ipv4: "147.251.0.0/16", comment: "https only from MUNI" }
For more complex setups, you can use filters, e.g. to open ports 80 and 443 to known IP ranges only:
- hosts: all
vars:
my_ranges:
- { ipv4: "147.251.0.0/16", comment: "allow from MUNI" }
- { ipv6: "2001:718:801::/48", comment: "allow from MUNI" }
- { ipv4: "147.32.0.0/16", comment: "allow from CVUT" }
- { ipv4: "147.228.0.0/16", comment: "allow from ZCU" }
firewall_open_tcp_ports: "{{ (my_ranges|map('combine',{'port':'http'})|list) + (my_ranges|map('combine',{'port':'https'})|list) }}"
roles:
- role: cesnet.firewall
TCP ports exported from Docker containers are exposed in the FORWARD chain which is processed before INPUT chain, so the firewall rules from the INPUT chain do not apply to containers, see Docker and iptables.
You can put rules into the chain DOCKER-USER for rejecting packets before they reach the chain DOCKER.
Docker manipulates only IPv4 iptables. Ports exported from containers do listen on all IPv6 addresses, so rules from the INPUT chain do apply to IPv6 packets. Thus you have to explicitly allow a port exported from a container to be available over IPv6.
In short, if you want to restrict access to a port 9000 exported from a container in both IPv4 and IPv6, do it like this:
- role: cesnet.firewall
vars:
firewall_open_tcp_ports:
- { port: 9000, ipv6: "2001:718:801::/48", comment: "accept 9000 only from MUNI over IPv6" }
- { port: 9000, ipv6: "2001:718:1:13::/64", comment: "accept 9000 only from CESNET VPN over IPv6" }
firewall_docker_rules:
- port: 9000
only:
- { ipv4: "147.251.0.0/16", comment: "portainer from MUNI"}
- { ipv4: "78.128.246.160/32", comment: "portainer from CESNET eduVPN" }
- { ipv4: "78.128.247.175/32", comment: "portainer from CESNET eduVPN" }