Sunday, November 17, 2013

Configure IPTables with Ansible.

If you need to configure IPTables on the fly using Ansible, this is a really quick way to do it (and requires no extra dependencies). This mechanism relies on the lineinfile module, which allows you to idempotently add/verify/remove lines of text inside a file.  I then use with_items and list all of the protocols and ports I want available on the box.

* Note, this was validated on Ansible 1.4.0.


#
# This is an example Ansible playbook.
#
- hosts: all
  tasks:
    - name: Open the correct IPTables ports
      lineinfile: dest=/etc/sysconfig/iptables
                  regexp="^-A INPUT -p {{item.protocol}} -m {{item.protocol}} --dport {{item.port}} -j ACCEPT$"
                  line="-A INPUT -p {{item.protocol}} -m {{item.protocol}} --dport {{item.port}} -j ACCEPT"
                  insertafter="^:OUTPUT ACCEPT \[\d*:\d*\]$"
      with_items:
        - { protocol: tcp, port: 80 }
        - { protocol: tcp, port: 443 }
        - { protocol: tcp, port: 389 }
        - { protocol: tcp, port: 636 }
        - { protocol: tcp, port: 88 }
        - { protocol: tcp, port: 464 }
        - { protocol: tcp, port: 53 }
        - { protocol: udp, port: 88 }
        - { protocol: udp, port: 464 }
        - { protocol: udp, port: 53 }
        - { protocol: udp, port: 123 }
      notify:
        - restart iptables

  handlers:
      - name: restart iptables
        action: service name=iptables state=restarted

#
This is (admittedly) a very simple example, but you should be able to see the value in the approach and adapt it to more complex scenarios.

Good luck!

3 comments:

  1. Worked well for me but I made a couple of small changes:

    lineinfile: dest=/etc/sysconfig/iptables
    regexp="^-A INPUT -p {{item.protocol}} -m state --state NEW -m {{item.protocol}} --dport {{item.port}} -j ACCEPT$"
    line="-A INPUT -p {{item.protocol}} -m state --state NEW -m {{item.protocol}} --dport {{item.port}} -j ACCEPT"
    insertbefore="^-A INPUT -j REJECT --reject-with icmp-host-prohibited$"
    with_items:
    - { protocol: tcp, port: 80 }
    ....

    Firstly, I use the iptables 'state' module and the rule only applies to the NEW state. Secondly, the new rule is inserted before the final rule in my INPUT table which rejects all connections with an ICMP host-prohibited (rather than adding it to the top of the INPUT table

    ReplyDelete
  2. This was very helpful. Thanks a lot for sharing!

    ReplyDelete
  3. If you guys want a more flexible solution, I created a role to manage iptables rules: https://github.com/mikegleasonjr/ansible-role-firewall

    Thank you

    ReplyDelete

Note: Only a member of this blog may post a comment.