├── .ansible-lint ├── .github ├── FUNDING.yml └── workflows │ ├── ci.yml │ ├── release.yml │ └── stale.yml ├── .gitignore ├── .yamllint ├── LICENSE ├── README.md ├── defaults └── main.yml ├── handlers └── main.yml ├── meta └── main.yml ├── molecule └── default │ ├── converge.yml │ └── molecule.yml ├── tasks ├── disable-other-firewalls.yml └── main.yml └── templates ├── firewall.bash.j2 ├── firewall.init.j2 └── firewall.unit.j2 /.ansible-lint: -------------------------------------------------------------------------------- 1 | skip_list: 2 | - 'yaml' 3 | - 'role-name' 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | --- 3 | github: geerlingguy 4 | patreon: geerlingguy 5 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: CI 3 | 'on': 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | schedule: 9 | - cron: "0 1 * * 1" 10 | 11 | defaults: 12 | run: 13 | working-directory: 'geerlingguy.firewall' 14 | 15 | jobs: 16 | 17 | lint: 18 | name: Lint 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Check out the codebase. 22 | uses: actions/checkout@v4 23 | with: 24 | path: 'geerlingguy.firewall' 25 | 26 | - name: Set up Python 3. 27 | uses: actions/setup-python@v5 28 | with: 29 | python-version: '3.x' 30 | 31 | - name: Install test dependencies. 32 | run: pip3 install yamllint 33 | 34 | - name: Lint code. 35 | run: | 36 | yamllint . 37 | 38 | molecule: 39 | name: Molecule 40 | runs-on: ubuntu-latest 41 | strategy: 42 | matrix: 43 | distro: 44 | - rockylinux9 45 | - ubuntu2404 46 | - debian12 47 | 48 | steps: 49 | - name: Check out the codebase. 50 | uses: actions/checkout@v4 51 | with: 52 | path: 'geerlingguy.firewall' 53 | 54 | - name: Set up Python 3. 55 | uses: actions/setup-python@v5 56 | with: 57 | python-version: '3.x' 58 | 59 | - name: Install test dependencies. 60 | run: pip3 install ansible molecule molecule-plugins[docker] docker 61 | 62 | - name: Run Molecule tests. 63 | run: molecule test 64 | env: 65 | PY_COLORS: '1' 66 | ANSIBLE_FORCE_COLOR: '1' 67 | MOLECULE_DISTRO: ${{ matrix.distro }} 68 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This workflow requires a GALAXY_API_KEY secret present in the GitHub 3 | # repository or organization. 4 | # 5 | # See: https://github.com/marketplace/actions/publish-ansible-role-to-galaxy 6 | # See: https://github.com/ansible/galaxy/issues/46 7 | 8 | name: Release 9 | 'on': 10 | push: 11 | tags: 12 | - '*' 13 | 14 | defaults: 15 | run: 16 | working-directory: 'geerlingguy.firewall' 17 | 18 | jobs: 19 | 20 | release: 21 | name: Release 22 | runs-on: ubuntu-latest 23 | steps: 24 | - name: Check out the codebase. 25 | uses: actions/checkout@v4 26 | with: 27 | path: 'geerlingguy.firewall' 28 | 29 | - name: Set up Python 3. 30 | uses: actions/setup-python@v5 31 | with: 32 | python-version: '3.x' 33 | 34 | - name: Install Ansible. 35 | run: pip3 install ansible-core 36 | 37 | - name: Trigger a new import on Galaxy. 38 | run: >- 39 | ansible-galaxy role import --api-key ${{ secrets.GALAXY_API_KEY }} 40 | $(echo ${{ github.repository }} | cut -d/ -f1) $(echo ${{ github.repository }} | cut -d/ -f2) 41 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Close inactive issues 3 | 'on': 4 | schedule: 5 | - cron: "55 18 * * 0" # semi-random time 6 | 7 | jobs: 8 | close-issues: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | issues: write 12 | pull-requests: write 13 | steps: 14 | - uses: actions/stale@v8 15 | with: 16 | days-before-stale: 120 17 | days-before-close: 60 18 | exempt-issue-labels: bug,pinned,security,planned 19 | exempt-pr-labels: bug,pinned,security,planned 20 | stale-issue-label: "stale" 21 | stale-pr-label: "stale" 22 | stale-issue-message: | 23 | This issue has been marked 'stale' due to lack of recent activity. If there is no further activity, the issue will be closed in another 30 days. Thank you for your contribution! 24 | 25 | Please read [this blog post](https://www.jeffgeerling.com/blog/2020/enabling-stale-issue-bot-on-my-github-repositories) to see the reasons why I mark issues as stale. 26 | close-issue-message: | 27 | This issue has been closed due to inactivity. If you feel this is in error, please reopen the issue or file a new issue with the relevant details. 28 | stale-pr-message: | 29 | This pr has been marked 'stale' due to lack of recent activity. If there is no further activity, the issue will be closed in another 30 days. Thank you for your contribution! 30 | 31 | Please read [this blog post](https://www.jeffgeerling.com/blog/2020/enabling-stale-issue-bot-on-my-github-repositories) to see the reasons why I mark issues as stale. 32 | close-pr-message: | 33 | This pr has been closed due to inactivity. If you feel this is in error, please reopen the issue or file a new issue with the relevant details. 34 | repo-token: ${{ secrets.GITHUB_TOKEN }} 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.retry 2 | */__pycache__ 3 | *.pyc 4 | .cache 5 | 6 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | 4 | rules: 5 | line-length: 6 | max: 120 7 | level: warning 8 | 9 | ignore: | 10 | .github/workflows/stale.yml 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Jeff Geerling 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ansible Role: Firewall (iptables) 2 | 3 | [![CI](https://github.com/geerlingguy/ansible-role-firewall/actions/workflows/ci.yml/badge.svg)](https://github.com/geerlingguy/ansible-role-firewall/actions/workflows/ci.yml) 4 | 5 | Installs an iptables-based firewall for Linux. Supports both IPv4 (`iptables`) and IPv6 (`ip6tables`). 6 | 7 | This firewall aims for simplicity over complexity, and only opens a few specific ports for incoming traffic (configurable through Ansible variables). If you have a rudimentary knowledge of `iptables` and/or firewalls in general, this role should be a good starting point for a secure system firewall. 8 | 9 | After the role is run, a `firewall` init service will be available on the server. You can use `service firewall [start|stop|restart|status]` to control the firewall. 10 | 11 | ## Requirements 12 | 13 | None. 14 | 15 | ## Role Variables 16 | 17 | Available variables are listed below, along with default values (see `defaults/main.yml`): 18 | 19 | ```yaml 20 | firewall_state: started 21 | firewall_enabled_at_boot: true 22 | ``` 23 | 24 | Controls the state of the firewall service; whether it should be running (`firewall_state`) and/or enabled on system boot (`firewall_enabled_at_boot`). 25 | 26 | ```yaml 27 | firewall_flush_rules_and_chains: true 28 | ``` 29 | 30 | Whether to flush all rules and chains whenever the firewall is restarted. Set this to `false` if there are other processes managing iptables (e.g. Docker). 31 | 32 | ```yaml 33 | firewall_template: firewall.bash.j2 34 | ``` 35 | 36 | The template to use when generating firewall rules. 37 | 38 | ```yaml 39 | firewall_allowed_tcp_ports: 40 | - "22" 41 | - "80" 42 | ... 43 | firewall_allowed_udp_ports: [] 44 | ``` 45 | 46 | A list of TCP or UDP ports (respectively) to open to incoming traffic. 47 | 48 | ```yaml 49 | firewall_forwarded_tcp_ports: 50 | - { src: "22", dest: "2222" } 51 | - { src: "80", dest: "8080" } 52 | firewall_forwarded_udp_ports: [] 53 | ``` 54 | 55 | Forward `src` port to `dest` port, either TCP or UDP (respectively). 56 | 57 | ```yaml 58 | firewall_additional_rules: [] 59 | firewall_ip6_additional_rules: [] 60 | ``` 61 | 62 | Any additional (custom) rules to be added to the firewall (in the same format you would add them via command line, e.g. `iptables [rule]`/`ip6tables [rule]`). A few examples of how this could be used: 63 | 64 | ```yaml 65 | # Allow only the IP 167.89.89.18 to access port 4949 (Munin). 66 | firewall_additional_rules: 67 | - "iptables -A INPUT -p tcp --dport 4949 -s 167.89.89.18 -j ACCEPT" 68 | 69 | # Allow only the IP 214.192.48.21 to access port 3306 (MySQL). 70 | firewall_additional_rules: 71 | - "iptables -A INPUT -p tcp --dport 3306 -s 214.192.48.21 -j ACCEPT" 72 | ``` 73 | 74 | See [Iptables Essentials: Common Firewall Rules and Commands](https://www.digitalocean.com/community/tutorials/iptables-essentials-common-firewall-rules-and-commands) for more examples. 75 | 76 | ```yaml 77 | firewall_log_dropped_packets: true 78 | ``` 79 | 80 | Whether to log dropped packets to syslog (messages will be prefixed with "Dropped by firewall: "). 81 | 82 | ```yaml 83 | firewall_disable_firewalld: false 84 | firewall_disable_ufw: false 85 | ``` 86 | 87 | Set to `true` to disable firewalld (installed by default on RHEL/CentOS) or ufw (installed by default on Ubuntu), respectively. 88 | 89 | ```yaml 90 | firewall_enable_ipv6: true 91 | ``` 92 | 93 | Set to `false` to disable configuration of ip6tables (for example, if your `GRUB_CMDLINE_LINUX` contains `ipv6.disable=1`). 94 | 95 | ## Dependencies 96 | 97 | None. 98 | 99 | ## Example Playbook 100 | 101 | ```yaml 102 | - hosts: server 103 | vars_files: 104 | - vars/main.yml 105 | roles: 106 | - { role: geerlingguy.firewall } 107 | ``` 108 | 109 | *Inside `vars/main.yml`*: 110 | 111 | ```yaml 112 | firewall_allowed_tcp_ports: 113 | - "22" 114 | - "25" 115 | - "80" 116 | ``` 117 | 118 | ## License 119 | 120 | MIT / BSD 121 | 122 | ## Author Information 123 | 124 | This role was created in 2014 by [Jeff Geerling](https://www.jeffgeerling.com/), author of [Ansible for DevOps](https://www.ansiblefordevops.com/). 125 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | firewall_state: started 3 | firewall_enabled_at_boot: true 4 | 5 | firewall_flush_rules_and_chains: true 6 | 7 | firewall_template: firewall.bash.j2 8 | firewall_allowed_tcp_ports: 9 | - "22" 10 | - "25" 11 | - "80" 12 | - "443" 13 | firewall_allowed_udp_ports: [] 14 | firewall_forwarded_tcp_ports: [] 15 | firewall_forwarded_udp_ports: [] 16 | firewall_additional_rules: [] 17 | firewall_enable_ipv6: true 18 | firewall_ip6_additional_rules: [] 19 | firewall_log_dropped_packets: true 20 | 21 | # Set to true to ensure other firewall management software is disabled. 22 | firewall_disable_firewalld: false 23 | firewall_disable_ufw: false 24 | -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart firewall 3 | service: name=firewall state=restarted 4 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependencies: [] 3 | 4 | galaxy_info: 5 | role_name: firewall 6 | author: geerlingguy 7 | description: Simple iptables firewall for most Unix-like systems. 8 | company: "Midwestern Mac, LLC" 9 | license: "license (BSD, MIT)" 10 | min_ansible_version: 2.10 11 | platforms: 12 | - name: Debian 13 | versions: 14 | - all 15 | - name: Ubuntu 16 | versions: 17 | - all 18 | galaxy_tags: 19 | - networking 20 | - system 21 | - security 22 | - firewall 23 | - iptables 24 | - tcp 25 | -------------------------------------------------------------------------------- /molecule/default/converge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Converge 3 | hosts: all 4 | #become: true 5 | 6 | vars: 7 | # Added to prevent test failures in CI. 8 | firewall_enable_ipv6: false 9 | 10 | # Added for a test. 11 | firewall_allowed_tcp_ports: 12 | - "9123" 13 | 14 | pre_tasks: 15 | - name: Update apt cache. 16 | apt: update_cache=true cache_valid_time=1200 17 | when: ansible_os_family == 'Debian' 18 | changed_when: false 19 | 20 | roles: 21 | - role: geerlingguy.firewall 22 | -------------------------------------------------------------------------------- /molecule/default/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | role_name_check: 1 3 | dependency: 4 | name: galaxy 5 | options: 6 | ignore-errors: true 7 | driver: 8 | name: docker 9 | platforms: 10 | - name: instance 11 | image: "geerlingguy/docker-${MOLECULE_DISTRO:-rockylinux9}-ansible:latest" 12 | command: ${MOLECULE_DOCKER_COMMAND:-""} 13 | volumes: 14 | - /sys/fs/cgroup:/sys/fs/cgroup:rw 15 | cgroupns_mode: host 16 | privileged: true 17 | pre_build_image: true 18 | provisioner: 19 | name: ansible 20 | playbooks: 21 | converge: ${MOLECULE_PLAYBOOK:-converge.yml} 22 | scenario: 23 | test_sequence: 24 | - destroy 25 | - dependency 26 | - syntax 27 | - create 28 | - prepare 29 | - converge 30 | - idempotence 31 | - check 32 | - side_effect 33 | - verify 34 | - destroy 35 | -------------------------------------------------------------------------------- /tasks/disable-other-firewalls.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Check if firewalld package is installed (on RHEL). 3 | command: yum list installed firewalld 4 | register: firewalld_installed 5 | ignore_errors: true 6 | changed_when: false 7 | when: 8 | - ansible_os_family == "RedHat" 9 | - firewall_disable_firewalld 10 | check_mode: false 11 | 12 | - name: Disable the firewalld service (on RHEL, if configured). 13 | service: 14 | name: firewalld 15 | state: stopped 16 | enabled: false 17 | when: 18 | - ansible_os_family == "RedHat" 19 | - firewall_disable_firewalld 20 | - firewalld_installed.rc == 0 21 | 22 | - name: Check if ufw package is installed (on Ubuntu). 23 | command: service ufw status 24 | register: ufw_installed 25 | ignore_errors: true 26 | changed_when: false 27 | when: 28 | - ansible_distribution == "Ubuntu" 29 | - firewall_disable_ufw 30 | check_mode: false 31 | 32 | - name: Disable the ufw firewall (on Ubuntu, if configured). 33 | service: 34 | name: ufw 35 | state: stopped 36 | enabled: false 37 | when: 38 | - ansible_distribution == "Ubuntu" 39 | - firewall_disable_ufw 40 | - ufw_installed.rc == 0 41 | 42 | - name: Check if ufw package is installed (on Archlinux). 43 | command: pacman -Q ufw 44 | register: ufw_installed 45 | ignore_errors: true 46 | changed_when: false 47 | when: 48 | - ansible_distribution == "Archlinux" 49 | - firewall_disable_ufw 50 | check_mode: false 51 | 52 | - name: Disable the ufw firewall (on Archlinux, if configured). 53 | service: 54 | name: ufw 55 | state: stopped 56 | enabled: false 57 | when: 58 | - ansible_distribution == "Archlinux" 59 | - firewall_disable_ufw 60 | - ufw_installed.rc == 0 61 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure iptables is present. 3 | package: name=iptables state=present 4 | 5 | - name: Flush iptables the first time playbook runs. 6 | command: > 7 | iptables -F 8 | creates=/etc/firewall.bash 9 | 10 | - name: Copy firewall script into place. 11 | template: 12 | src: "{{ firewall_template | default(firewall_template)}}" 13 | dest: /etc/firewall.bash 14 | owner: root 15 | group: root 16 | mode: 0744 17 | notify: restart firewall 18 | 19 | - name: Copy firewall init script into place. 20 | template: 21 | src: firewall.init.j2 22 | dest: /etc/init.d/firewall 23 | owner: root 24 | group: root 25 | mode: 0755 26 | when: "ansible_service_mgr != 'systemd'" 27 | 28 | - name: Copy firewall systemd unit file into place (for systemd systems). 29 | template: 30 | src: firewall.unit.j2 31 | dest: /etc/systemd/system/firewall.service 32 | owner: root 33 | group: root 34 | mode: 0644 35 | when: "ansible_service_mgr == 'systemd'" 36 | 37 | - name: Configure the firewall service. 38 | service: 39 | name: firewall 40 | state: "{{ firewall_state }}" 41 | enabled: "{{ firewall_enabled_at_boot }}" 42 | 43 | - import_tasks: disable-other-firewalls.yml 44 | when: firewall_disable_firewalld or firewall_disable_ufw 45 | -------------------------------------------------------------------------------- /templates/firewall.bash.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # iptables firewall. 3 | # 4 | # This file should be located at /etc/firewall.bash, and is meant to work with 5 | # the `geerlingguy.firewall` Ansible role. 6 | # 7 | # Common port reference: 8 | # 22: SSH 9 | # 25: SMTP 10 | # 80: HTTP 11 | # 123: NTP 12 | # 443: HTTPS 13 | # 2222: SSH alternate 14 | # 8080: HTTP alternate 15 | # 16 | # @author Jeff Geerling 17 | 18 | # No spoofing. 19 | if [ -e /proc/sys/net/ipv4/conf/all/rp_filter ] 20 | then 21 | for filter in /proc/sys/net/ipv4/conf/*/rp_filter 22 | do 23 | echo 1 > $filter 24 | done 25 | fi 26 | 27 | # Set the default rules. 28 | iptables -P INPUT ACCEPT 29 | iptables -P FORWARD ACCEPT 30 | iptables -P OUTPUT ACCEPT 31 | 32 | {% if firewall_flush_rules_and_chains %} 33 | # Remove all rules and chains. 34 | iptables -t nat -F 35 | iptables -t mangle -F 36 | iptables -F 37 | iptables -X 38 | {% endif %} 39 | 40 | # Accept traffic from loopback interface (localhost). 41 | iptables -A INPUT -i lo -j ACCEPT 42 | 43 | # Forwarded ports. 44 | {# Add a rule for each forwarded port #} 45 | {% for forwarded_port in firewall_forwarded_tcp_ports %} 46 | iptables -t nat -I PREROUTING -p tcp --dport {{ forwarded_port.src }} -j REDIRECT --to-port {{ forwarded_port.dest }} 47 | iptables -t nat -I OUTPUT -p tcp -o lo --dport {{ forwarded_port.src }} -j REDIRECT --to-port {{ forwarded_port.dest }} 48 | {% endfor %} 49 | {% for forwarded_port in firewall_forwarded_udp_ports %} 50 | iptables -t nat -I PREROUTING -p udp --dport {{ forwarded_port.src }} -j REDIRECT --to-port {{ forwarded_port.dest }} 51 | iptables -t nat -I OUTPUT -p udp -o lo --dport {{ forwarded_port.src }} -j REDIRECT --to-port {{ forwarded_port.dest }} 52 | {% endfor %} 53 | 54 | # Open ports. 55 | {# Add a rule for each open port #} 56 | {% for port in firewall_allowed_tcp_ports %} 57 | iptables -A INPUT -p tcp -m tcp --dport {{ port }} -j ACCEPT 58 | {% endfor %} 59 | {% for port in firewall_allowed_udp_ports %} 60 | iptables -A INPUT -p udp -m udp --dport {{ port }} -j ACCEPT 61 | {% endfor %} 62 | 63 | # Accept icmp ping requests. 64 | iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT 65 | 66 | # Allow NTP traffic for time synchronization. 67 | iptables -A OUTPUT -p udp --dport 123 -j ACCEPT 68 | iptables -A INPUT -p udp --sport 123 -j ACCEPT 69 | 70 | # Additional custom rules. 71 | {% for rule in firewall_additional_rules %} 72 | {{ rule }} 73 | {% endfor %} 74 | 75 | # Allow established connections: 76 | iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 77 | 78 | # Log EVERYTHING (ONLY for Debug). 79 | # iptables -A INPUT -j LOG 80 | 81 | {% if firewall_log_dropped_packets %} 82 | # Log other incoming requests (all of which are dropped) at 15/minute max. 83 | iptables -A INPUT -m limit --limit 15/minute -j LOG --log-level 7 --log-prefix "Dropped by firewall: " 84 | {% endif %} 85 | 86 | # Drop all other traffic. 87 | iptables -A INPUT -j DROP 88 | 89 | {% if firewall_enable_ipv6 %} 90 | # Configure IPv6 if ip6tables is present. 91 | if [ -x "$(which ip6tables 2>/dev/null)" ]; then 92 | 93 | {% if firewall_flush_rules_and_chains %} 94 | # Remove all rules and chains. 95 | ip6tables -F 96 | ip6tables -X 97 | {% endif %} 98 | 99 | # Accept traffic from loopback interface (localhost). 100 | ip6tables -A INPUT -i lo -j ACCEPT 101 | 102 | # Open ports. 103 | {# Add a rule for each open port #} 104 | {% for port in firewall_allowed_tcp_ports %} 105 | ip6tables -A INPUT -p tcp -m tcp --dport {{ port }} -j ACCEPT 106 | {% endfor %} 107 | {% for port in firewall_allowed_udp_ports %} 108 | ip6tables -A INPUT -p udp -m udp --dport {{ port }} -j ACCEPT 109 | {% endfor %} 110 | 111 | # Accept icmp ping requests. 112 | ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT 113 | 114 | # Allow NTP traffic for time synchronization. 115 | ip6tables -A OUTPUT -p udp --dport 123 -j ACCEPT 116 | ip6tables -A INPUT -p udp --sport 123 -j ACCEPT 117 | 118 | # Additional custom rules. 119 | {% for rule in firewall_ip6_additional_rules %} 120 | {{ rule }} 121 | {% endfor %} 122 | 123 | # Allow established connections: 124 | ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 125 | 126 | # Log EVERYTHING (ONLY for Debug). 127 | # ip6tables -A INPUT -j LOG 128 | 129 | {% if firewall_log_dropped_packets %} 130 | # Log other incoming requests (all of which are dropped) at 15/minute max. 131 | ip6tables -A INPUT -m limit --limit 15/minute -j LOG --log-level 7 --log-prefix "Dropped by firewall: " 132 | {% endif %} 133 | 134 | # Drop all other traffic. 135 | ip6tables -A INPUT -j DROP 136 | 137 | fi 138 | {% endif %} 139 | -------------------------------------------------------------------------------- /templates/firewall.init.j2: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # /etc/init.d/firewall 3 | # 4 | # Firewall init script, to be used with /etc/firewall.bash by Jeff Geerling. 5 | # 6 | # @author Jeff Geerling 7 | 8 | ### BEGIN INIT INFO 9 | # Provides: firewall 10 | # Required-Start: $remote_fs $syslog 11 | # Required-Stop: $remote_fs $syslog 12 | # Default-Start: 2 3 4 5 13 | # Default-Stop: 0 1 6 14 | # Short-Description: Start firewall at boot time. 15 | # Description: Enable the firewall. 16 | ### END INIT INFO 17 | 18 | # Carry out specific functions when asked to by the system 19 | case "$1" in 20 | start) 21 | echo "Starting firewall." 22 | /etc/firewall.bash 23 | ;; 24 | stop) 25 | echo "Stopping firewall." 26 | iptables -F 27 | if [ -x "$(which ip6tables 2>/dev/null)" ]; then 28 | ip6tables -F 29 | fi 30 | ;; 31 | restart) 32 | echo "Restarting firewall." 33 | /etc/firewall.bash 34 | ;; 35 | status) 36 | echo -e "`iptables -L -n`" 37 | EXIT=4 # program or service status is unknown 38 | NUMBER_OF_RULES=$(iptables-save | grep '^\-' | wc -l) 39 | if [ 0 -eq $NUMBER_OF_RULES ]; then 40 | EXIT=3 # program is not running 41 | else 42 | EXIT=0 # program is running or service is OK 43 | fi 44 | exit $EXIT 45 | ;; 46 | *) 47 | echo "Usage: /etc/init.d/firewall {start|stop|status|restart}" 48 | exit 1 49 | ;; 50 | esac 51 | 52 | exit 0 53 | -------------------------------------------------------------------------------- /templates/firewall.unit.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Firewall 3 | After=syslog.target network.target 4 | 5 | [Service] 6 | Type=oneshot 7 | ExecStart=/etc/firewall.bash 8 | ExecStop=/sbin/iptables -F 9 | RemainAfterExit=yes 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | --------------------------------------------------------------------------------