From 8ca1ca46a966d45502d055fff16b0416b49ee009 Mon Sep 17 00:00:00 2001 From: Kevin Carter Date: Mon, 12 Aug 2019 13:35:37 -0500 Subject: [PATCH] Add firewall pruning and protocal parsing The original puppet manifest would prune non-persistent firewall rules from the save file whenever needed. This change reimplements that functionality. In addition to pruning the original puppet manifest had special protocol handling for particular types and states. This change also reimplements that functionality. These new functions have been added to our molicule tests to ensure we're validating functionality. Change-Id: Ibe4bed6b27cb774dabc40e28a61032bc399c2eae Signed-off-by: Kevin Carter --- .../roles/tripleo-firewall/handlers/main.yml | 21 +++++++++++ .../firewall-add-complex/playbook.yml | 8 +++++ .../firewall-remove-complex/playbook.yml | 16 +++++++++ .../roles/tripleo-firewall/tasks/main.yml | 21 ++++++++--- .../tasks/tripleo_firewall_add.yml | 17 +++++---- ...ml => tripleo_firewall_protocol_rules.yml} | 36 +++++++------------ .../tasks/tripleo_firewall_state.yml | 28 +++++++++++++++ 7 files changed, 113 insertions(+), 34 deletions(-) rename tripleo_ansible/roles/tripleo-firewall/tasks/{tripleo_firewall_remove.yml => tripleo_firewall_protocol_rules.yml} (60%) create mode 100644 tripleo_ansible/roles/tripleo-firewall/tasks/tripleo_firewall_state.yml diff --git a/tripleo_ansible/roles/tripleo-firewall/handlers/main.yml b/tripleo_ansible/roles/tripleo-firewall/handlers/main.yml index 511b98c21..e3991dca0 100644 --- a/tripleo_ansible/roles/tripleo-firewall/handlers/main.yml +++ b/tripleo_ansible/roles/tripleo-firewall/handlers/main.yml @@ -31,6 +31,7 @@ enabled: true name: tripleo-iptables.service failed_when: false + become: true listen: Save firewall rules - name: Enable tripleo-ip6tables service @@ -38,4 +39,24 @@ enabled: true name: tripleo-ip6tables.service failed_when: false + become: true + listen: Save firewall rules + +- name: Find non-persistent rules + command: egrep -l 'comment.*(neutron-|ironic-inspector)' /etc/sysconfig/iptables /etc/sysconfig/ip6tables + failed_when: false + changed_when: false + register: neutron_rules + become: true + listen: Save firewall rules + +- name: Remove non-persistent line(s) + lineinfile: + path: "{{ item }}" + state: absent + regexp: 'comment.*(neutron-|ironic-inspector)' + when: + - item.find('v=' ~ '^/') == -1 + loop: "{{ neutron_rules.stdout_lines }}" + become: true listen: Save firewall rules diff --git a/tripleo_ansible/roles/tripleo-firewall/molecule/firewall-add-complex/playbook.yml b/tripleo_ansible/roles/tripleo-firewall/molecule/firewall-add-complex/playbook.yml index 2649be7ea..7d1b9da3b 100644 --- a/tripleo_ansible/roles/tripleo-firewall/molecule/firewall-add-complex/playbook.yml +++ b/tripleo_ansible/roles/tripleo-firewall/molecule/firewall-add-complex/playbook.yml @@ -39,3 +39,11 @@ - 12123 - 12200-12210 chain: test-chain + '004 gre networks': + proto: 'gre' + '005 vrrp networks': + proto: 'vrrp' + '006 neutron-test': + dport: 2211 + '006 ironic-inspector': + dport: 2212 diff --git a/tripleo_ansible/roles/tripleo-firewall/molecule/firewall-remove-complex/playbook.yml b/tripleo_ansible/roles/tripleo-firewall/molecule/firewall-remove-complex/playbook.yml index a2bcd0026..d2b0e706b 100644 --- a/tripleo_ansible/roles/tripleo-firewall/molecule/firewall-remove-complex/playbook.yml +++ b/tripleo_ansible/roles/tripleo-firewall/molecule/firewall-remove-complex/playbook.yml @@ -45,3 +45,19 @@ extras: ensure: 'absent' chain: test-chain + '004 gre networks': + proto: 'gre' + extras: + ensure: 'absent' + '005 vrrp networks': + proto: 'vrrp' + extras: + ensure: 'absent' + '006 neutron-test': + dport: 2211 + extras: + ensure: 'absent' + '006 ironic-inspector': + dport: 2212 + extras: + ensure: 'absent' diff --git a/tripleo_ansible/roles/tripleo-firewall/tasks/main.yml b/tripleo_ansible/roles/tripleo-firewall/tasks/main.yml index 43708e723..b73d161d7 100644 --- a/tripleo_ansible/roles/tripleo-firewall/tasks/main.yml +++ b/tripleo_ansible/roles/tripleo-firewall/tasks/main.yml @@ -28,6 +28,18 @@ tags: - always +- name: Check rule set + fail: + msg: >- + `{{ item['rule_name'] }}` firewall rule cannot be created. TCP or UDP rules + for INPUT or OUTPUT need sport or dport defined. + when: + - ((item['rule']['proto'] | default('tcp')) in ['tcp', 'udp']) and + (item['rule']['dport'] is undefined) and + ((item['rule']['chain'] | default('INPUT')) != 'FORWARD') and + ((item['rule']['table'] | default('filter')) != 'nat') + loop: "{{ tripleo_firewall_rules | dict2items(key_name='rule_name', value_name='rule') }}" + - name: Firewall add block become: true block: @@ -46,12 +58,11 @@ include_tasks: tripleo_firewall_add.yml when: - item['rule']['dport'] is defined - - tripleo_firewall_port_states[(item['rule']['extras'] | default({}))['ensure'] | default('enabled')] == 'present' loop: "{{ tripleo_firewall_rules | dict2items(key_name='rule_name', value_name='rule') }}" - - name: Disable filewall port config - include_tasks: tripleo_firewall_remove.yml + - name: Enable filewall protocol config + include_tasks: tripleo_firewall_protocol_rules.yml when: - - item['rule']['dport'] is defined - - tripleo_firewall_port_states[(item['rule']['extras'] | default({}))['ensure'] | default('enabled')] == 'absent' + - item['rule']['proto'] is defined + - item['rule']['dport'] is undefined loop: "{{ tripleo_firewall_rules | dict2items(key_name='rule_name', value_name='rule') }}" diff --git a/tripleo_ansible/roles/tripleo-firewall/tasks/tripleo_firewall_add.yml b/tripleo_ansible/roles/tripleo-firewall/tasks/tripleo_firewall_add.yml index 252caeec0..0c98dd346 100644 --- a/tripleo_ansible/roles/tripleo-firewall/tasks/tripleo_firewall_add.yml +++ b/tripleo_ansible/roles/tripleo-firewall/tasks/tripleo_firewall_add.yml @@ -36,11 +36,14 @@ exit ${EXIT_CODE} when: - (item['rule']['chain'] | default('INPUT')) != 'INPUT' + - tripleo_firewall_port_states[(item['rule']['extras'] | default({}))['ensure'] | default('enabled')] == "present" register: iptables_chain changed_when: iptables_chain.rc == 99 failed_when: not (iptables_chain.rc in [0, 99]) -- name: Add firewall service rule (ipv4) +- include_tasks: tripleo_firewall_state.yml + +- name: Firewall port rule (ipv4) iptables: table: "{{ item['rule']['table'] | default(omit) }}" chain: "{{ item['rule']['chain'] | default('INPUT') }}" @@ -51,10 +54,11 @@ source: "{{ item['rule']['source'] | default(omit) }}" comment: "{{ item['rule_name'] }} ipv4" jump: "{{ item['rule']['jump'] | default('ACCEPT') }}" - ctstate: "{{ item['rule']['ctstate'] | default('NEW') }}" + ctstate: "{{ tripleo_ctstate }}" ip_version: ipv4 - state: "present" + state: "{{ tripleo_firewall_port_states[(item['rule']['extras'] | default({}))['ensure'] | default('enabled')] }}" when: + - (item['rule']['proto'] | default('tcp')) != 'ipv6' - item['rule']['source'] | default('127.0.0.1') | ipv4 loop: "{{ (item['rule']['dport'] is iterable) | ternary(item['rule']['dport'], [item['rule']['dport']]) }}" loop_control: @@ -62,7 +66,7 @@ notify: - Save firewall rules -- name: Add firewall service rule (ipv6) +- name: Firewall port rule (ipv6) iptables: table: "{{ item['rule']['table'] | default(omit) }}" chain: "{{ item['rule']['chain'] | default('INPUT') }}" @@ -73,10 +77,11 @@ source: "{{ item['rule']['source'] | default(omit) }}" comment: "{{ item['rule_name'] }} ipv6" jump: "{{ item['rule']['jump'] | default('ACCEPT') }}" - ctstate: "{{ item['rule']['ctstate'] | default('NEW') }}" + ctstate: "{{ tripleo_ctstate }}" ip_version: ipv6 - state: "present" + state: "{{ tripleo_firewall_port_states[(item['rule']['extras'] | default({}))['ensure'] | default('enabled')] }}" when: + - (item['rule']['proto'] | default('tcp')) != 'ipv4' - item['rule']['source'] | default('::') | ipv6 loop: "{{ (item['rule']['dport'] is iterable) | ternary(item['rule']['dport'], [item['rule']['dport']]) }}" loop_control: diff --git a/tripleo_ansible/roles/tripleo-firewall/tasks/tripleo_firewall_remove.yml b/tripleo_ansible/roles/tripleo-firewall/tasks/tripleo_firewall_protocol_rules.yml similarity index 60% rename from tripleo_ansible/roles/tripleo-firewall/tasks/tripleo_firewall_remove.yml rename to tripleo_ansible/roles/tripleo-firewall/tasks/tripleo_firewall_protocol_rules.yml index 69e7d0eda..e4af4d001 100644 --- a/tripleo_ansible/roles/tripleo-firewall/tasks/tripleo_firewall_remove.yml +++ b/tripleo_ansible/roles/tripleo-firewall/tasks/tripleo_firewall_protocol_rules.yml @@ -15,46 +15,36 @@ # under the License. -- name: Remove firewall service rule (ipv4) +- include_tasks: tripleo_firewall_state.yml + +- name: Firewall protocol rule (ipv4) iptables: table: "{{ item['rule']['table'] | default(omit) }}" chain: "{{ item['rule']['chain'] | default('INPUT') }}" in_interface: "{{ item['rule']['interface'] | default(omit) }}" - protocol: "{{ item['rule']['proto'] | default('tcp') }}" - destination_port: "{{ port | replace('-', ':') }}" + protocol: "{{ item['rule']['proto'] }}" source_port: "{{ item['rule']['sport'] | default(omit) | replace('-', ':') }}" source: "{{ item['rule']['source'] | default(omit) }}" comment: "{{ item['rule_name'] }} ipv4" jump: "{{ item['rule']['jump'] | default('ACCEPT') }}" - ctstate: "{{ item['rule']['ctstate'] | default('NEW') }}" + ctstate: "{{ tripleo_ctstate }}" ip_version: ipv4 - state: "absent" + state: "{{ tripleo_firewall_port_states[(item['rule']['extras'] | default({}))['ensure'] | default('enabled')] }}" when: - - item['rule']['source'] | default('127.0.0.1') | ipv4 - loop: "{{ (item['rule']['dport'] is iterable) | ternary(item['rule']['dport'], [item['rule']['dport']]) }}" - loop_control: - loop_var: port - notify: - - Save firewall rules + - item['rule']['proto'] != 'ipv6' -- name: Remove firewall service rule (ipv6) +- name: Firewall protocol rule (ipv6) iptables: table: "{{ item['rule']['table'] | default(omit) }}" chain: "{{ item['rule']['chain'] | default('INPUT') }}" in_interface: "{{ item['rule']['interface'] | default(omit) }}" - protocol: "{{ item['rule']['proto'] | default('tcp') }}" - destination_port: "{{ port | replace('-', ':') }}" + protocol: "{{ item['rule']['proto'] }}" source_port: "{{ item['rule']['sport'] | default(omit) | replace('-', ':') }}" source: "{{ item['rule']['source'] | default(omit) }}" - comment: "{{ item['rule_name'] }} ipv6" + comment: "{{ item['rule_name'] }} ipv4" jump: "{{ item['rule']['jump'] | default('ACCEPT') }}" - ctstate: "{{ item['rule']['ctstate'] | default('NEW') }}" + ctstate: "{{ tripleo_ctstate }}" ip_version: ipv6 - state: "absent" + state: "{{ tripleo_firewall_port_states[(item['rule']['extras'] | default({}))['ensure'] | default('enabled')] }}" when: - - item['rule']['source'] | default('::') | ipv6 - loop: "{{ (item['rule']['dport'] is iterable) | ternary(item['rule']['dport'], [item['rule']['dport']]) }}" - loop_control: - loop_var: port - notify: - - Save firewall rules + - item['rule']['proto'] != 'ipv4' diff --git a/tripleo_ansible/roles/tripleo-firewall/tasks/tripleo_firewall_state.yml b/tripleo_ansible/roles/tripleo-firewall/tasks/tripleo_firewall_state.yml new file mode 100644 index 000000000..b8869d86d --- /dev/null +++ b/tripleo_ansible/roles/tripleo-firewall/tasks/tripleo_firewall_state.yml @@ -0,0 +1,28 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +- name: Set gre state fact + set_fact: + tripleo_ctstate: [] + when: + - (item['rule']['proto'] | default('tcp')) == 'gre' + +- name: Set general state fact + set_fact: + tripleo_ctstate: "{{ item['rule']['ctstate'] | default(item['rule']['state'] | default('NEW')) }}" + when: + - (item['rule']['proto'] | default('tcp')) != 'gre'