Iptables management with ansible in huge environment
Solution 1:
ufw
Ansible
has a ufw
module in order to handle firewall rules. In roles/common/tasks/main.yml
, which is included in all my servers, I have (among other things):
- name: Install ufw
apt: name=ufw
- name: Allow ssh through firewall
ufw: proto=tcp port=22 rule=allow
- name: Set ufw policy
ufw: state=enabled direction=incoming policy=deny
Edit: It is necessary to allow ssh before setting default policy to "deny" (originally it was opposite above), otherwise you may be locked out in between the two steps.
Then, in each role, I have additional firewall rules for that role. For example, in roles/nginx/tasks/main.yml
, I have (among other things) this:
- name: Allow nginx firewall
ufw: proto=tcp port=80 rule=allow
- name: Allow nginx ssl firewall
ufw: proto=tcp port=443 rule=allow
So all my nginx servers have ports 80 and 443 opened.
This way you can build whatever common configuration you want and add additional rules in more specific roles.
ferm
If you have rules which ufw
cannot handle, one solution I think would work nicely is ferm
; it can do almost anything, and you can configure it to read rules from directories such as /etc/ferm/input.d/
, /etc/ferm/output.d/
, /etc/ferm/forward.d/
, etc. You could make your common
role prepare the essential ferm
configuration and then have other roles drop files in these directories.
plain iptables
Your requirement to have ansible
specify rules in addition to rules specified in another way is unusual and apparently defies most of the point for using ansible
. Unfortunately I don't see any way to do it other than with plain iptables
, which would be quite ugly. Here is an example of opening up port 80 in roles/nginx/tasks/main.yml
(untested):
- name: Check if port 80 is allowed
shell: iptables -L | grep -q "Allow http" && echo -n yes || echo -n no
register: check_allow_http
changed_when: no
always_run: yes
- name: Allow port 80
command: >
iptables -A INPUT -p tcp -m tcp --dport 80
-m comment --comment "Allow http" -j ACCEPT
when: check_allow_http.stdout == "no"
notify:
- Save iptables
where Save iptables
is a handler that executes iptables-save
. All the above is quite tedious to write, but it might be appropriate, especially if you have only a few rules to manage with ansible
.
Solution 2:
lineinfile
If you want to manage rules in your iptables configuration without overwriting existing rules or centrally managing iptables in a template, use Ansible's lineinfile module:
- name: ensure iptables allows established and related traffic
lineinfile:
dest=/etc/sysconfig/iptables
state=present
regexp="^.*INPUT.*ESTABLISHED,RELATED.*ACCEPT"
insertafter="^:OUTPUT " line="-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT"
backup=yes
notify: restart iptables
- name: ensure iptables is configured to allow ssh traffic (port 22/tcp)
lineinfile:
dest=/etc/sysconfig/iptables
state=present
regexp="^.*INPUT.*tcp.*22.*ACCEPT"
insertafter="^.*INPUT.*ESTABLISHED,RELATED.*ACCEPT" line="-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT"
backup=yes
notify: restart iptables
Here's the "restart iptables" handler:
- name: restart iptables
service: name=iptables state=restarted