Adding iptables Rules With Ansible

16th February 2014

Many systems and applications require certain access to certain ports and protocols. When installing these systems using Ansible it is necessary to also open up the needed ports so that the systems can function correctly. As there is no iptables module in Ansible the shell command is needed to add the iptables rules.

As an example, here is a task that adds a iptables rule to allow Apache to communicate on port 80.

  1. - name: Apache | add apache iptable rule
  2. command: /sbin/iptables -I INPUT 1 -p tcp --dport http -j ACCEPT -m comment --comment "Apache"
  3. sudo: true

Once this is in place you might need to save and/or restart iptables in order to get the rule to be permanently saved. The following two rules will save the iptables rule and restart the iptables service. Note that these commands are specific to Ubuntu and so might not work on your system setup.

  1. - name: save iptables
  2. command: iptables-save
  3. sudo: true
  4.  
  5. - name: restart iptables
  6. service: name=ufw state=restarted
  7. sudo: true

This allows Apache to communicate, but the trouble is that when the Ansible task is run a second time a second iptables rule will be added. This can cause problems, especially when Ansible is run over and over again to maintain the configuration of the server. For this reason another step must be added to detect for the existence of the rule before it is added. This is done by using the shell module to print the available iptables rules out and store them into a variable. The Ansible keyword 'register' allows any returned value from the current task to be saved as a variable, in this case the variable registered is called 'iptablesrules'.

  1. - name: Apache | get iptables rules
  2. shell: iptables -L
  3. register: iptablesrules
  4. sudo: true

With this in place we can now run the iptables insertion command only when we cannot find a rule that matches the one that we want to add. The find function is run on the iptablesrules.stdout parameter to find the word "Apache" within the contents. This matches the comment that was used in the iptables rule creation. and Here is the modified task.

  1. - name: Apache | add apache iptable rule
  2. command: /sbin/iptables -I INPUT 1 -p tcp --dport http -j ACCEPT -m comment --comment "Apache"
  3. sudo: true
  4. when: iptablesrules.stdout.find("Apache") == -1

The only problem now is that when checking that an Ansible playbook will execute as expected (by using the --check flag) the added conditional will fail. This is because the iptablesrules variable that is generated is not done in this case and so Ansible will error and complain about a missing variable. The way around this it to force the iptables rules variable registry task to always run, even if we are in check mode. To do this we add the always_run flag to the task.

  1. - name: Apache | get iptables rules
  2. shell: iptables -L
  3. register: iptablesrules
  4. always_run: yes
  5. sudo: true

Here is the entire playbook in full. Note that it is better practice to use create the iptables save and restart tasks as handlers and notify them from the needed tasks. This allows them to be reused when generating iptables rules for other services.

  1. ---
  2. - name: Apache | get iptables rules
  3. shell: iptables -L
  4. register: iptablesrules
  5. always_run: yes
  6. sudo: true
  7.  
  8. - name: Apache | add apache iptable rule
  9. command: /sbin/iptables -I INPUT 1 -p tcp --dport http -j ACCEPT -m comment --comment "Apache"
  10. sudo: true
  11. when: iptablesrules.stdout.find("Apache") == -1
  12.  
  13. - name: save iptables
  14. command: iptables-save
  15. sudo: true
  16.  
  17. - name: restart iptables
  18. service: name= ufw state=restarted
  19. sudo: true

Comments

Permalink
Great playbook, thanks for sharing. I just added changed_when: false to the "get iptables rules" task so that it does not report as changed when running the playbook. - name: Apache | get iptables rules shell: iptables -L register: iptablesrules always_run: yes changed_when: false # Never report as changed sudo: true

Submitted by iamc on Wed, 04/30/2014 - 09:42

Permalink
iptables-save doesn't save the iptables...

Submitted by Tom on Wed, 05/04/2016 - 14:43

Permalink
Another way to do it...
  1. -name: Save iptables rules
  2. command: /sbin/service iptables save
  3. sudo: True

Submitted by Am Elemara on Wed, 09/07/2016 - 11:15

Add new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.