{"id":13753466,"url":"https://github.com/mikegleasonjr/ansible-role-firewall","last_synced_at":"2025-05-05T19:55:52.826Z","repository":{"id":2110378,"uuid":"45733520","full_name":"mikegleasonjr/ansible-role-firewall","owner":"mikegleasonjr","description":"A role to manage iptables rules which doesn't suck.","archived":false,"fork":false,"pushed_at":"2024-09-10T21:25:08.000Z","size":32,"stargazers_count":95,"open_issues_count":10,"forks_count":38,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-03-02T20:57:38.558Z","etag":null,"topics":["ansible","ansible-role","firewall-roles","iptables","iptables-rules","ipv4","ipv6"],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mikegleasonjr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-11-07T11:23:22.000Z","updated_at":"2025-01-26T23:19:42.000Z","dependencies_parsed_at":"2024-09-24T15:38:48.346Z","dependency_job_id":null,"html_url":"https://github.com/mikegleasonjr/ansible-role-firewall","commit_stats":{"total_commits":30,"total_committers":9,"mean_commits":"3.3333333333333335","dds":"0.30000000000000004","last_synced_commit":"24adf7171323f2f94eb54d120814008387c00842"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikegleasonjr%2Fansible-role-firewall","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikegleasonjr%2Fansible-role-firewall/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikegleasonjr%2Fansible-role-firewall/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikegleasonjr%2Fansible-role-firewall/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mikegleasonjr","download_url":"https://codeload.github.com/mikegleasonjr/ansible-role-firewall/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243544669,"owners_count":20308168,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","ansible-role","firewall-roles","iptables","iptables-rules","ipv4","ipv6"],"created_at":"2024-08-03T09:01:22.801Z","updated_at":"2025-03-14T08:07:03.402Z","avatar_url":"https://github.com/mikegleasonjr.png","language":"Shell","funding_links":[],"categories":["iptables"],"sub_categories":[],"readme":"Ansible Firewall Role\n=========\n\n[![Build Status](https://travis-ci.org/mikegleasonjr/ansible-role-firewall.svg?branch=master)](https://travis-ci.org/mikegleasonjr/ansible-role-firewall)\n[![Ansible Galaxy](https://img.shields.io/badge/galaxy-mikegleasonjr.firewall-5bbdbf.svg?style=flat)](https://galaxy.ansible.com/detail#/role/5878)\n\nAfter I found out `UFW` was too limited in terms of functionalities, I tried several firewall roles out there but none satisfied the requirements I had:\n\n- Support virtually all iptables rules from the start\n- Allow granular rules addition/overriding for specific hosts\n- Easily inject variables in the rules\n- Allow rules ordering\n- Simplicity (not having to learn how role variables would generate the rules)\n- Persistence (reload the rules at boot)\n\nThis role is an attempt to solve these requirements.\n\nIt supports **ipv4** and **ipv6*** on Debian and RedHat distributions. ipv6 rules are not configured by default. If you which to use them, don't forget to set `firewall_v6_configure` to `true`.\n\nRequirements\n------------\n\n* Ansible 2.4.0.0\n* `iptables` (installed by default on all official Debian and RedHat distributions)\n\nInstallation\n------------\n\n`$ ansible-galaxy install mikegleasonjr.firewall`\n\nRole Variables\n--------------\n\n`defaults/main.yml`:\n\n```\n---\nfirewall_v4_configure: true\nfirewall_v6_configure: false\n\nfirewall_v4_flush_rules:\n  - -F\n  - -X\n  - -t raw -F\n  - -t raw -X\n  - -t nat -F\n  - -t nat -X\n  - -t mangle -F\n  - -t mangle -X\nfirewall_v4_default_rules:\n  001 default policies:\n    - -P INPUT ACCEPT\n    - -P OUTPUT ACCEPT\n    - -P FORWARD DROP\n  002 allow loopback:\n    - -A INPUT -i lo -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT\n  003 allow ping replies:\n    - -A INPUT -p icmp --icmp-type echo-request -j ACCEPT\n    - -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT\n  100 allow established related:\n    - -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\n  200 allow ssh:\n    - -A INPUT -p tcp --dport ssh -j ACCEPT\n  999 drop everything:\n    - -P INPUT DROP\nfirewall_v4_group_rules: {}\nfirewall_v4_host_rules: {}\n\nfirewall_v6_flush_rules:\n  - -F\n  - -X\n  - -t raw -F\n  - -t raw -X\n  - -t nat -F\n  - -t nat -X\n  - -t mangle -F\n  - -t mangle -X\nfirewall_v6_default_rules:\n  001 default policies:\n    - -P INPUT ACCEPT\n    - -P OUTPUT ACCEPT\n    - -P FORWARD DROP\n  002 allow loopback:\n    - -A INPUT -i lo -s ::1/128 -d ::1/128 -j ACCEPT\n  003 allow ping replies:\n    - -A INPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT\n    - -A OUTPUT -p icmpv6 --icmpv6-type echo-reply -j ACCEPT\n  100 allow established related:\n    - -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\n  200 allow ssh:\n    - -A INPUT -p tcp --dport ssh -j ACCEPT\n  999 drop everything:\n    - -P INPUT DROP\nfirewall_v6_group_rules: {}\nfirewall_v6_host_rules: {}\n```\n\nThe keys to the `*_rules` dictionaries, except the flush rules, can be anything. They are only used for rules **ordering** and **overriding**. On rules generation, the keys are sorted alphabetically. That's why I chose here the 001s and 999s.\n\nThose defaults will generate the following script to be executed on the host (for ipv4):\n\n```\n#!/bin/sh\n# Ansible managed: \u003credacted\u003e\n\n# flush rules\niptables -F\niptables -X\niptables -t raw -F\niptables -t raw -X\niptables -t nat -F\niptables -t nat -X\niptables -t mangle -F\niptables -t mangle -X\n\n# 001 default policies\niptables -P INPUT ACCEPT\niptables -P OUTPUT ACCEPT\niptables -P FORWARD DROP\n\n# 002 allow loopback\niptables -A INPUT -i lo -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT\n\n# 003 allow ping replies\niptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT\niptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT\n\n# 100 allow established related\niptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\n\n# 200 allow ssh\niptables -A INPUT -p tcp --dport ssh -j ACCEPT\n\n# 999 drop everything\niptables -P INPUT DROP\n```\n\nAs you can see, you have complete control over the rules syntax.\n\n`$ iptables -L -n` on the host then shows...\n\n```\nChain INPUT (policy DROP)\ntarget     prot opt source               destination\nACCEPT     all  --  0.0.0.0/0            0.0.0.0/0\nACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0            icmptype 8\nACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED\nACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:22\n\nChain FORWARD (policy DROP)\ntarget     prot opt source               destination\n\nChain OUTPUT (policy ACCEPT)\ntarget     prot opt source               destination\nACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0            icmptype 0\n```\n\nNow that takes care of the default rules. What about overriding?\n\nYou can change the rules for specific hosts and groups instead of re-defining everything. Rules in `firewall_v4_host_rules` will be merged with `firewall_v4_group_rules`, and then the result will be merged back with the defaults. Same thing for ipv6.\n\nThis allows 3 levels of rules definition and overriding. I simply chose the names to match how the variable precedence works in Ansible (`all` -\u003e `group` -\u003e `host`). See the example playbook below to see rules overriding in action.\n\nExample Playbook (ipv4)\n----------------\n\n```\n- hosts: all\n  roles:\n    - mikegleasonjr.firewall\n```\n\nin `group_vars/all.yml` you could define the default rules for all your hosts:\n\n```\nfirewall_v4_default_rules:\n  001 default policies:\n    - -P INPUT ACCEPT\n    - -P OUTPUT ACCEPT\n    - -P FORWARD DROP\n  002 allow loopback:\n    - -A INPUT -i lo -j ACCEPT\n  003 allow ping replies:\n    - -A INPUT -p icmp --icmp-type echo-request -j ACCEPT\n    - -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT\n  100 allow established related:\n    - -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\n  200 allow ssh limiting brute force:\n    - -I INPUT -p tcp -d {{ hostvars[inventory_hostname]['ansible_eth1']['ipv4']['address'] }} --dport 22 -m state --state NEW -m recent --set\n    - -I INPUT -p tcp -d {{ hostvars[inventory_hostname]['ansible_eth1']['ipv4']['address'] }} --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP\n  999 drop everything:\n    - -P INPUT DROP\n```\n\nin `group_vars/webservers.yml` you would open up port 80:\n\n```\nfirewall_v4_group_rules:\n  400 allow web traffic:\n    - -A INPUT -p tcp --dport http -j ACCEPT\n```\n\nin `host_vars/secureweb.yml` you would want to open https as well and remove ssh logins:\n\n```\nfirewall_v4_host_rules:\n  400 allow web traffic:\n    - -A INPUT -p tcp --dport http -j ACCEPT    # need to redefine this one as well because the whole key is overwritten\n    - -A INPUT -p tcp --dport https -j ACCEPT\n  200 allow ssh limiting brute force: []\n```\n\nTo \"delete\" rules, you just assign an empty list to an existing dictionary key.\n\nTo summarize, rules in `firewall_v4_host_rules` will overwrite rules in `firewall_v4_group_rules`, and then rules in `firewall_v4_group_rules` will overwrite rules in `firewall_v4_default_rules`.\n\nYou can play with the rules and see the generated script on the host at the following location: `/etc/iptables.v4.generated` and `/etc/iptables.v6.generated`.\n\nDependencies\n------------\n\nnone\n\nLicense\n-------\n\nBSD\n\nContributing\n-------\n\nA vagrant environment has been provided to test the role on different distributions. Add your tests in `tests.yml` and...\n\n```\n$ vagrant up\n$ vagrant provision\n```\n\nAuthor Information\n------------------\n\nMike Gleason jr Couturier (mikegleasonjr@gmail.com)\n\nOther roles from the same author:\n\n- [swap](https://github.com/mikegleasonjr/ansible-role-swap)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikegleasonjr%2Fansible-role-firewall","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmikegleasonjr%2Fansible-role-firewall","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikegleasonjr%2Fansible-role-firewall/lists"}