Coder Social home page Coder Social logo

mikegleasonjr / ansible-role-firewall Goto Github PK

View Code? Open in Web Editor NEW
92.0 14.0 36.0 30 KB

A role to manage iptables rules which doesn't suck.

License: BSD 2-Clause "Simplified" License

Shell 100.00%
ansible-role firewall-roles iptables ansible iptables-rules ipv4 ipv6

ansible-role-firewall's People

Contributors

alo-is avatar conorsch avatar mikegleasonjr avatar rudd-o avatar xionox avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ansible-role-firewall's Issues

Backup the generated files

Could you add backup: yes on the rules templates tasks so that an horrible mistake could be easily undone ?

By the way, thanks for this role and the smart use of combining the hashes.

Support `--check` mode

The role currently fails when called with --check on the command line, due to registered vars being undefined in conditional logic. We can leverage the check_mode: no task-level argument to work around on select tasks. Docs here.

Note that the check_mode param requires Ansible v2.2+. Given the nasty CVE-2016-9587, please consider requiring Ansible v2.2.1+.

group_vars/webservers

Hi
i need some clarification with this. This path does not exist so i guess i have to create a folder called group_vars and inside that folder create the webservers yaml like in your example 👍

in group_vars/webservers.yml you would open up port 80:

firewall_v4_group_rules:
400 allow web traffic:
- -A INPUT -p tcp --dport http -j ACCEPT

problem is when i run the play i get this error

ERROR! playbooks must be a list of plays and it complains about this line :
firewall_v4_default_rules:
^ here

RHEL7 / CentOS7 disable firewalld

In the currenmt version of this role, iptables is installed, enabled and started. In RHEL7 and CentOS7, the alternative firewall daemon "firewalld" is used by default. This daemon has to be stopped and most important disabled.

I therefore added the following task to the "persist-redhat.yml" file. This task would be best to be executed right before iptables service is started.

- name: Ensure firewalld service is disabled and stopped
  systemd:
    name: firewalld
    state: stopped
    enabled: no
    masked: yes
  register: firewalld_result
  failed_when: "firewalld_result is failed and 'Could not find the requested service' not in firewalld_result.msg"
  when: ansible_os_family == 'RedHat' and ansible_distribution_major_version >= '7'

This task ensures that the firewalld is not only stopped but also disabled and masked. Masking avoids accidental start ofg this service even manually. The when should prevent the role from failing if the firewalld service is not installed on the system.

I have seen that you prefere the one-line version of the tasks, I hope this is still helpful for you. I have tested this on CentOS 7.5 and it should workj without modification as well on RHEL 7.5.

If you prefere a pull request, please let me know.

Ensure iptables is really installed.

We had a PR (#21) that made sure iptables was installed.

Is it really the case on supported OSes (centos-6, centos-7, ubuntu-xenial, ubuntu-trusty), that maybe iptables is not installed?

Maybe adding couldn't hurt.

Which BSD-License exactly?

Would you be so kind an give more detail as to which BSD-License you are using?

There are three versions I think:

  • Original / 4-clause
  • Modified / 3-clause
  • Simplified / 2-clause

Modified and simple would be compatible with GPL, while the original version is not. Simplified would be compatible with commercial licenses.

Thanks in advance!

Beware if your host is in more than one group

My inventory defines hosts and groups.
Each group has a firewall_v4_group_rules dictionary defined.
I was expecting to get a merge of all the firewall_v4_group_rules from each group a host belongs to, but instead, the host only got the rules defined from one group.

Example:

[all]
myhost

[web]
myhost

[database]
myhost

Then group_vars/web.yaml and group_vars/database.yaml define each firewall_v4_group_rules

As a result, myhost only receives rules from one of the 2 groups.

I can work around this issue by setting globally for ansible "hash_behaviour = merge" but is there a way to get this in the role (without changing ansible config) ? Maybe at the template level (I'm not an expert)?

Issue with group_vars/webservers.yml example

Hi,

Testing this out and I'm trying to get the example below working. The rules in all.yml are picked up fine, but the rules in webservers.yml are not.

/etc/ansible/inventory/hosts:

[webservers]
example.machine

/etc/ansible/playbooks/fw.ywl:

- hosts: all
  roles:
    - mikegleasonjr.firewall

/etc/ansible/inventory/group_vars/all.yml:

firewall_v4_default_rules:
  001 default policies:
    - -P INPUT ACCEPT
    - -P OUTPUT ACCEPT
    - -P FORWARD DROP
  002 allow loopback:
    - -A INPUT -i lo -j ACCEPT
  003 allow ping replies:
    - -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
    - -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
  100 allow established related:
    - -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
  200 allow ssh limiting brute force:
    - -I INPUT -p tcp -d {{ hostvars[inventory_hostname]['ansible_eth1']['ipv4']['address'] }} --dport     22 -m state --state NEW -m recent --set
    - -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
  999 drop everything:
- -P INPUT DROP

/etc/ansible/inventory/group_vars/webservers.yml:

---
firewall_v4_group_rules:
  005 allow http traffic:
    - -A INPUT -p tcp --dport 80 -j ACCEPT
    - -A INPUT -p tcp --dport 443 -j ACCEPT

I'm running Ansible like so:

#ansible-playbook -i /etc/ansible/inventory/hosts /etc/ansible/playbooks/fw.ywl -vvv

I've went over the webservers.yml file multiple times and the spacing seems ok and there are no typos that I can see.

TASK: [mikegleasonjr.firewall | Load v4 rules] ********************************
skipping: [example.machine]

As a test, I created another playbook file /etc/ansible/inventory/group_vars/mailservers.yml

---
firewall_v4_group_rules:
  1100 allow mail traffic:
    - -A INPUT -p tcp --dport 25 -j ACCEPT
    - -A INPUT -p tcp --dport 587  -j ACCEPT
    - -A INPUT -p tcp --dport 465  -j ACCEPT
    - -A INPUT -p tcp --dport 110  -j ACCEPT
    - -A INPUT -p tcp --dport 143  -j ACCEPT
    - -A INPUT -p tcp --dport 993  -j ACCEPT
    - -A INPUT -p tcp --dport 995  -j ACCEPT

And this one works? What could be wrong? What's the best way to get a better picture as to why the rules for the webservers group are being skipped?

Errors reported by iptables during rule loading should cause task to fail

The iptables load task blithely ignores errors printed to stderr via iptables, for example:

$ sudo /etc/iptables.v4.generated
iptables v1.4.21: unknown option "--dstport"
Try `iptables -h' or 'iptables --help' for more information.
iptables v1.4.21: unknown option "--dstport"
Try `iptables -h' or 'iptables --help' for more information.

The mistake is a typo: --dstport isn't a valid option, and should instead be --dport. Iptables caught that error and reported it, but the misconfiguration didn't percolate up and cause the role execution to fail.

Version comparision for RedHat based distributions

In file tasks/persist-redhat.yml to compare version number it's better to use filter |int >= 7 and |int < 7 - then the comparision will work correctly also for versions bigger than 9. This change will make this role working properly also on Fedora 28 servers - as it happened to me..

It's mentioned here:

Tip: Sometimes you’ll get back a variable that’s a string and you’ll want to do a math operation comparison on it. You can do this like so:

tasks:

  • shell: echo "only on Red Hat 6, derivatives, and later"
    when: ansible_facts['os_family'] == "RedHat" and ansible_facts['lsb']['major_release']|int >= 6

Deprecation warning: "Instead of using `result|changed` instead use `result is changed`."

Using Ansible 2.5 I get a warning e.g. for this place :

[DEPRECATION WARNING]: Using tests as filters is deprecated. Instead of using `result|changed` instead use `result is changed`. This feature will be removed in version 2.9. Deprecation 
warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.

It seems it can be easy corrected by using "is changed". And the output will be nice, clean after that.

Fails when used on a system without 'nat' or any other default table

On a server I am not allowed to have "nat" table. And unfortunately on that system I cannot use this role, because those initial commands from "templates/generated.v4.j2" cause failures.

Probably for users like me it would be useful to change this initial cleanup commands from:

iptables -t raw -F
iptables -t raw -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X

to:

iptables -t raw -F >/dev/null 2>&1 || true
iptables -t raw -X >/dev/null 2>&1 || true
iptables -t nat -F >/dev/null 2>&1 || true
iptables -t nat -X >/dev/null 2>&1 || true
iptables -t mangle -F >/dev/null 2>&1 || true
iptables -t mangle -X >/dev/null 2>&1 || true

Because failures on them are not interesting for admin - I know that I don't have those tables - because I didn't configured using them. But it's good to keep those cleanup commands, so that if any of those tables is present, it gets cleaned up by default.

The same for ip6tables.

Of course I can use a modified copy of this role, but it would be great to have it working by default.

Multiple group for host

Hi,
Same way as #32, my host is in multiple group with different rules to merge but I dont want to turn on the global merge config option.

I updated the template in this way to solve my need :
{% set _ = merged.update(firewall_v4_group_rules) %}
{% for group in group_names %}
{% set _ = merged.update( lookup('vars', 'firewall_v4_group_' + group + '_rules', default="" ) ) %}
{% endfor %}

Lookup on the host group an merge var like firewall_v4_group__rules or and empty string if not defined. The "firewall_v4_group_rules stay in place to keep initial feature.

[DEPRECATION WARNING]: The use of 'include' for tasks has been deprecated.

Since 2.4, "include" statement is marked as deprecated. It can be easy fixed by just changing it to "include_tasks" which will only include the file when the condition matches.

For completness, here the complete warning generated by ansible 2.4.2.0.

[DEPRECATION WARNING]: The use of 'include' for tasks has been deprecated. Use 'import_tasks' for static inclusions or 'include_tasks' for dynamic inclusions. This feature will be removed in a future release. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
[DEPRECATION WARNING]: include is kept for backwards compatibility but usage is discouraged. The module documentation details page may explain more about this rationale.. This feature will be removed in a future release. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.

The file "tasks/main.yml" would therefore look like this.

- include_tasks: rules.yml

- include_tasks: persist-debian.yml
  when: ansible_os_family == 'Debian'

- include_tasks: persist-redhat.yml
when: ansible_os_family == 'RedHat'

I guess its not worth creating a fork and a pull request for this, isn't it?

Errors reported by iptables during rule loading should cause task to fail (tables)

Related in spirit to #5, which added support for failing based on stderr output from the iptables wrapper script. In #5 we discussed "unknown option" but that doesn't catch the "Table does not exist" error:

$ sudo /etc/iptables.v4.generated
iptables v1.4.21: can't initialize iptables table `nat': Table does not exist (do you need to insmod?)
Perhaps iptables or your kernel needs to be upgraded.

I propose expanding the failed_when logic on the rule load task to fail if the string "Table does not exist" is found in the stderr.

Add some flags to disable IPv6 rules generation

After implementing ip6tables in #8 & #9, I just thought that sometimes, ip6tables rule generation is not needed.

It might be nice to add some kind of flag variable to avoid IPv6 rules generation, to keep the node configuration.

group_vars rules are not intercepted between groups

I have some group based rules:
0. ansible/roles/mikegleasonjr.firewall:


---
firewall_v4_default_rules:
  001 default policies:
    - -P INPUT ACCEPT
    - -P OUTPUT ACCEPT
    - -P FORWARD DROP
  002 allow loopback:
    - -A INPUT -i lo -j ACCEPT
  003 allow ping replies:
    - -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
    - -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
  100 allow established related:
    - -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
  200 allow ssh:
    - -A INPUT -p tcp --dport ssh -j ACCEPT 
  201 allow zabbix agent:
    - -A INPUT -p tcp --match multiport --dports 10050,10051 -j ACCEPT
  204 allow http:
    - -A INPUT -p tcp --dport 80 -j ACCEPT
  205 allow syslog:
    - -A INPUT -p udp --dport 514 -j ACCEPT
    - -A INPUT -p tcp --dport 514 -j ACCEPT
  250 allow haproxy web interface:
    - -A INPUT -p tcp --dport 8080 -j ACCEPT
  999 drop everything:
    - -P INPUT DROP

firewall_v4_group_rules: {}

firewall_v4_host_rules: {}

1.ansible/group_vars/sql_hosts:


---
firewall_v4_group_rules:
  320 Allow Percona XtraDB Cluster ports:
    - -A INPUT -p tcp --match multiport --dports 3306,4444,4567,4568 -j ACCEPT
  321 allow mysql through haproxy:
    - -A INPUT -p tcp --dport 13306 -j ACCEPT

2.ansible/group_vars/pbx_hosts:


---
firewall_v4_group_rules:
  300 allow sip and rtp:
    - -A INPUT -p udp --dport 5060 -j ACCEPT
    - -A INPUT -p tcp --dport 5060 -j ACCEPT
    - -A INPUT -p udp --match multiport --dports 10000:20000 -j ACCEPT
  301 allow T.38 UDPTL:
    - -A INPUT -p udp --match multiport --dports 4000:4999 -j ACCEPT
  302 allow voipmonitor sensor:
    - -A INPUT -p tcp --dport 5029 -j ACCEPT

3.In 'ansible/hosts' file I have some servers intercepted between groups:

[pbx_hosts]
srv1
srv2

[sql_hosts]
srv1
srv2
srv3

After applying playbook to all hosts I see only sql_hosts-based rules and not pbx_hosts-based:

[root@srv1 filter.d]# iptables -L -n
Chain INPUT (policy DROP)
target     prot opt source               destination
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0           icmp type 8
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           ctstate RELATED,ESTABLISHED
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:22
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           multiport dports 10050,10051
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:80
ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0           udp dpt:514
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:514
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:8080
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           multiport dports 3306,4444,4567,4568
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:13306

Chain FORWARD (policy DROP)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0           icmp type 0

I supposed I should have seen all rules I described in both files.

Should use iptables-persistent

This role should leverage the functionality available in the {iptables,netfilter}-persistent packages on Debian-based systems.

overlapping groups and their firewall rules

I run a complex ansible setup with many hosts and many overlapping groups. It sometimes happens that i have variables overlapping in my group_vars. I find myself not wanting to enable merge=yes in my ansible config so i kind of altered the iptables template.

Note: this only works with ansible version >= 2.5 due to the vars lookup. Also there are quite a lot of deprecation notices when running ansible 2.5 because of the when statements. You should use "result is changed" instead of the current "result|changed" (gotta love the ansible team ;) )

{% set merged = {} %}
{% set found_groups = hostvars[inventory_hostname].keys() | to_json | from_json | json_query('[?starts_with(@, 'firewall_v4_group')]') | sort %}

{% for rules in (['firewall_v4_default_rules'] + found_groups + ['firewall_v4_host_rules']) %}
{% set _ = merged.update(lookup('vars', rules)) %}
{{ rules }}
{% endfor %}

This way i can have 2 roles assigned to a host, lets say role_kafka and role_zookeeper and keep the firewall rules in seperate group files without having ansible overwrite the variable with whatever comes last.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.