From 0bb84bc58ea226e05b95ab200dd252b458637462 Mon Sep 17 00:00:00 2001
From: David Moreau-Simard <dmsimard@redhat.com>
Date: Sat, 21 Oct 2017 11:31:51 -0400
Subject: [PATCH] Persist iptables rules

We configured iptables rules but did not persist them.
This meant that rules would be flushed when restarting iptables or
the instance.

Change-Id: I9d90f55323a33d6a0f0dda1f7ab25d10984fa6cb
---
 roles/multi-node-bridge/tasks/main.yaml       |  4 +++
 roles/multi-node-firewall/tasks/main.yaml     |  7 ++--
 roles/persistent-firewall/README.rst          |  4 +++
 roles/persistent-firewall/tasks/main.yaml     | 22 ++++++++++++
 .../tasks/persist/Debian.yaml                 | 24 +++++++++++++
 .../tasks/persist/RedHat.yaml                 | 18 ++++++++++
 .../tasks/persist/Suse.yaml                   | 36 +++++++++++++++++++
 .../tasks/persist/Ubuntu_trusty.yaml          | 24 +++++++++++++
 .../tasks/persist/default.yaml                |  5 +++
 9 files changed, 141 insertions(+), 3 deletions(-)
 create mode 100644 roles/persistent-firewall/README.rst
 create mode 100644 roles/persistent-firewall/tasks/main.yaml
 create mode 100644 roles/persistent-firewall/tasks/persist/Debian.yaml
 create mode 100644 roles/persistent-firewall/tasks/persist/RedHat.yaml
 create mode 100644 roles/persistent-firewall/tasks/persist/Suse.yaml
 create mode 100644 roles/persistent-firewall/tasks/persist/Ubuntu_trusty.yaml
 create mode 100644 roles/persistent-firewall/tasks/persist/default.yaml

diff --git a/roles/multi-node-bridge/tasks/main.yaml b/roles/multi-node-bridge/tasks/main.yaml
index 20ee7e27e..70b1f79d8 100644
--- a/roles/multi-node-bridge/tasks/main.yaml
+++ b/roles/multi-node-bridge/tasks/main.yaml
@@ -14,3 +14,7 @@
     PATH: "{{ ansible_env.PATH }}:/sbin:/usr/sbin"
   when: inventory_hostname in groups['peers']
   static: no
+
+- name: Persist iptables rules
+  include_role:
+    name: persistent-firewall
diff --git a/roles/multi-node-firewall/tasks/main.yaml b/roles/multi-node-firewall/tasks/main.yaml
index bdca2401a..201bd2aee 100644
--- a/roles/multi-node-firewall/tasks/main.yaml
+++ b/roles/multi-node-firewall/tasks/main.yaml
@@ -37,6 +37,7 @@
     source: "{{ item }}"
     jump: ACCEPT
   with_items: "{{ ipv6_addresses }}"
-  when:
-    - ipv6_addresses is defined
-    - ipv6_addresses
+
+- name: Persist iptables rules
+  include_role:
+    name: persistent-firewall
diff --git a/roles/persistent-firewall/README.rst b/roles/persistent-firewall/README.rst
new file mode 100644
index 000000000..95964f1e6
--- /dev/null
+++ b/roles/persistent-firewall/README.rst
@@ -0,0 +1,4 @@
+Saves current iptables rules for both ipv4 and ipv6 and makes them persistent
+so that they are available if iptables or the instance is restarted.
+
+This role can be re-used more than once in order to persist new rules.
diff --git a/roles/persistent-firewall/tasks/main.yaml b/roles/persistent-firewall/tasks/main.yaml
new file mode 100644
index 000000000..984cf4e66
--- /dev/null
+++ b/roles/persistent-firewall/tasks/main.yaml
@@ -0,0 +1,22 @@
+- name: List current ipv4 rules
+  become: yes
+  command: iptables-save
+  changed_when: false
+  failed_when: false
+  register: iptables_rules
+
+- name: List current ipv6 rules
+  become: yes
+  command: ip6tables-save
+  changed_when: false
+  failed_when: false
+  register: ip6tables_rules
+
+- name: Configure persistent iptables rules
+  include: "{{ item }}"
+  static: no
+  with_first_found:
+    - "persist/{{ ansible_distribution }}_{{ ansible_distribution_release }}.yaml"
+    - "persist/{{ ansible_distribution }}.yaml"
+    - "persist/{{ ansible_os_family }}.yaml"
+    - "persist/default.yaml"
diff --git a/roles/persistent-firewall/tasks/persist/Debian.yaml b/roles/persistent-firewall/tasks/persist/Debian.yaml
new file mode 100644
index 000000000..8f4a04c05
--- /dev/null
+++ b/roles/persistent-firewall/tasks/persist/Debian.yaml
@@ -0,0 +1,24 @@
+- name: Install iptables-persistent
+  become: yes
+  package:
+    name: iptables-persistent
+    state: installed
+
+- name: Persist ipv4 rules
+  become: yes
+  copy:
+    content: "{{ iptables_rules.stdout }}"
+    dest: "/etc/iptables/rules.v4"
+
+- name: Persist ipv6 rules
+  become: yes
+  copy:
+    content: "{{ ip6tables_rules.stdout }}"
+    dest: "/etc/iptables/rules.v6"
+
+- name: Ensure netfilter-persistent is started
+  become: yes
+  service:
+    name: netfilter-persistent
+    state: started
+    enabled: yes
diff --git a/roles/persistent-firewall/tasks/persist/RedHat.yaml b/roles/persistent-firewall/tasks/persist/RedHat.yaml
new file mode 100644
index 000000000..55f7bd7f0
--- /dev/null
+++ b/roles/persistent-firewall/tasks/persist/RedHat.yaml
@@ -0,0 +1,18 @@
+- name: Persist ipv4 rules
+  become: yes
+  copy:
+    content: "{{ iptables_rules.stdout }}"
+    dest: "/etc/sysconfig/iptables"
+
+- name: Persist ipv6 rules
+  become: yes
+  copy:
+    content: "{{ ip6tables_rules.stdout }}"
+    dest: "/etc/sysconfig/ip6tables"
+
+- name: Ensure iptables is started
+  become: yes
+  service:
+    name: iptables
+    state: started
+    enabled: yes
diff --git a/roles/persistent-firewall/tasks/persist/Suse.yaml b/roles/persistent-firewall/tasks/persist/Suse.yaml
new file mode 100644
index 000000000..c37b46a95
--- /dev/null
+++ b/roles/persistent-firewall/tasks/persist/Suse.yaml
@@ -0,0 +1,36 @@
+- name: Persist ipv4 rules
+  become: yes
+  copy:
+    content: "{{ iptables_rules.stdout }}"
+    dest: "/etc/sysconfig/iptables"
+
+- name: Persist ipv6 rules
+  become: yes
+  copy:
+    content: "{{ ip6tables_rules.stdout }}"
+    dest: "/etc/sysconfig/ip6tables"
+
+- name: Set up SuSEfirewall2 custom rules to be loaded
+  become: yes
+  replace:
+    path: /etc/sysconfig/SuSEfirewall2
+    regexp: '^FW_CUSTOMRULES=.*$'
+    replace: 'FW_CUSTOMRULES="/etc/sysconfig/scripts/SuSEfirewall2-custom"'
+
+- name: Configure SuSEfirewall2 to restore saved rules on restart
+  become: yes
+  blockinfile:
+    path: /etc/sysconfig/scripts/SuSEfirewall2-custom
+    insertafter: EOF
+    content: |
+      fw_custom_after_finished() {
+          /usr/sbin/iptables-restore /etc/sysconfig/iptables
+          /usr/sbin/ip6tables-restore /etc/sysconfig/ip6tables
+      }
+
+- name: Ensure SuSEfirewall2 is started
+  become: yes
+  service:
+    name: SuSEfirewall2
+    state: started
+    enabled: yes
diff --git a/roles/persistent-firewall/tasks/persist/Ubuntu_trusty.yaml b/roles/persistent-firewall/tasks/persist/Ubuntu_trusty.yaml
new file mode 100644
index 000000000..a5cea2d9a
--- /dev/null
+++ b/roles/persistent-firewall/tasks/persist/Ubuntu_trusty.yaml
@@ -0,0 +1,24 @@
+- name: Install iptables-persistent
+  become: yes
+  package:
+    name: iptables-persistent
+    state: installed
+
+- name: Persist ipv4 rules
+  become: yes
+  copy:
+    content: "{{ iptables_rules.stdout }}"
+    dest: "/etc/iptables/rules.v4"
+
+- name: Persist ipv6 rules
+  become: yes
+  copy:
+    content: "{{ ip6tables_rules.stdout }}"
+    dest: "/etc/iptables/rules.v6"
+
+- name: Ensure iptables-persistent is started
+  become: yes
+  service:
+    name: iptables-persistent
+    state: started
+    enabled: yes
diff --git a/roles/persistent-firewall/tasks/persist/default.yaml b/roles/persistent-firewall/tasks/persist/default.yaml
new file mode 100644
index 000000000..003d8f55e
--- /dev/null
+++ b/roles/persistent-firewall/tasks/persist/default.yaml
@@ -0,0 +1,5 @@
+- name: Warn about unsupported distribution
+  debug:
+    msg: >
+      WARNING: {{ ansible_distribution }} is not supported by this role yet.
+      The execution of the job will continue without persisting iptables rules.