diff options
Diffstat (limited to 'roles/os_firewall')
-rw-r--r-- | roles/os_firewall/README.md | 5 | ||||
-rw-r--r-- | roles/os_firewall/defaults/main.yml | 8 | ||||
-rwxr-xr-x | roles/os_firewall/library/os_firewall_manage_iptables.py | 61 | ||||
-rw-r--r-- | roles/os_firewall/meta/main.yml | 13 | ||||
-rw-r--r-- | roles/os_firewall/tasks/firewall/firewalld.yml | 67 | ||||
-rw-r--r-- | roles/os_firewall/tasks/firewall/iptables.yml | 56 | ||||
-rw-r--r-- | roles/os_firewall/tasks/main.yml | 6 |
7 files changed, 77 insertions, 139 deletions
diff --git a/roles/os_firewall/README.md b/roles/os_firewall/README.md index 187d74b06..43db3cc74 100644 --- a/roles/os_firewall/README.md +++ b/roles/os_firewall/README.md @@ -4,10 +4,13 @@ OS Firewall OS Firewall manages firewalld and iptables firewall settings for a minimal use case (Adding/Removing rules based on protocol and port number). +Note: firewalld is not supported on Atomic Host +https://bugzilla.redhat.com/show_bug.cgi?id=1403331 + Requirements ------------ -None. +Ansible 2.2 Role Variables -------------- diff --git a/roles/os_firewall/defaults/main.yml b/roles/os_firewall/defaults/main.yml index c870a301a..4c544122f 100644 --- a/roles/os_firewall/defaults/main.yml +++ b/roles/os_firewall/defaults/main.yml @@ -1,9 +1,7 @@ --- os_firewall_enabled: True -# TODO: Upstream kubernetes only supports iptables currently -# TODO: it might be possible to still use firewalld if we wire up the created -# chains with the public zone (or the zone associated with the correct -# interfaces) -os_firewall_use_firewalld: False +# firewalld is not supported on Atomic Host +# https://bugzilla.redhat.com/show_bug.cgi?id=1403331 +os_firewall_use_firewalld: "{{ False if openshift.common.is_atomic | bool else True }}" os_firewall_allow: [] os_firewall_deny: [] diff --git a/roles/os_firewall/library/os_firewall_manage_iptables.py b/roles/os_firewall/library/os_firewall_manage_iptables.py index bd638b69b..8ba650994 100755 --- a/roles/os_firewall/library/os_firewall_manage_iptables.py +++ b/roles/os_firewall/library/os_firewall_manage_iptables.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # vim: expandtab:tabstop=4:shiftwidth=4 # pylint: disable=fixme, missing-docstring -from subprocess import call, check_output +import subprocess DOCUMENTATION = ''' --- @@ -29,7 +29,10 @@ class IpTablesAddRuleError(IpTablesError): class IpTablesRemoveRuleError(IpTablesError): - pass + def __init__(self, chain, msg, cmd, exit_code, output): # pylint: disable=too-many-arguments, line-too-long, redefined-outer-name + super(IpTablesRemoveRuleError, self).__init__(msg, cmd, exit_code, + output) + self.chain = chain class IpTablesSaveError(IpTablesError): @@ -37,14 +40,14 @@ class IpTablesSaveError(IpTablesError): class IpTablesCreateChainError(IpTablesError): - def __init__(self, chain, msg, cmd, exit_code, output): # pylint: disable=too-many-arguments, line-too-long, redefined-outer-name + def __init__(self, chain, msg, cmd, exit_code, output): # pylint: disable=too-many-arguments, line-too-long, redefined-outer-name super(IpTablesCreateChainError, self).__init__(msg, cmd, exit_code, output) self.chain = chain class IpTablesCreateJumpRuleError(IpTablesError): - def __init__(self, chain, msg, cmd, exit_code, output): # pylint: disable=too-many-arguments, line-too-long, redefined-outer-name + def __init__(self, chain, msg, cmd, exit_code, output): # pylint: disable=too-many-arguments, line-too-long, redefined-outer-name super(IpTablesCreateJumpRuleError, self).__init__(msg, cmd, exit_code, output) self.chain = chain @@ -53,7 +56,7 @@ class IpTablesCreateJumpRuleError(IpTablesError): # TODO: implement rollbacks for any events that were successful and an # exception was thrown later. For example, when the chain is created # successfully, but the add/remove rule fails. -class IpTablesManager(object): # pylint: disable=too-many-instance-attributes +class IpTablesManager(object): # pylint: disable=too-many-instance-attributes def __init__(self, module): self.module = module self.ip_version = module.params['ip_version'] @@ -68,8 +71,7 @@ class IpTablesManager(object): # pylint: disable=too-many-instance-attributes def save(self): try: - self.output.append(check_output(self.save_cmd, - stderr=subprocess.STDOUT)) + self.output.append(subprocess.check_output(self.save_cmd, stderr=subprocess.STDOUT)) except subprocess.CalledProcessError as ex: raise IpTablesSaveError( msg="Failed to save iptables rules", @@ -92,7 +94,7 @@ class IpTablesManager(object): # pylint: disable=too-many-instance-attributes else: cmd = self.cmd + ['-A'] + rule try: - self.output.append(check_output(cmd)) + self.output.append(subprocess.check_output(cmd)) self.changed = True self.save() except subprocess.CalledProcessError as ex: @@ -112,7 +114,7 @@ class IpTablesManager(object): # pylint: disable=too-many-instance-attributes else: cmd = self.cmd + ['-D'] + rule try: - self.output.append(check_output(cmd)) + self.output.append(subprocess.check_output(cmd)) self.changed = True self.save() except subprocess.CalledProcessError as ex: @@ -123,11 +125,19 @@ class IpTablesManager(object): # pylint: disable=too-many-instance-attributes def rule_exists(self, rule): check_cmd = self.cmd + ['-C'] + rule - return True if call(check_cmd) == 0 else False + return True if subprocess.call(check_cmd) == 0 else False + + @staticmethod + def port_as_argument(port): + if isinstance(port, int): + return str(port) + if isinstance(port, basestring): # noqa: F405 + return port.replace('-', ":") + return port def gen_rule(self, port, proto): return [self.chain, '-p', proto, '-m', 'state', '--state', 'NEW', - '-m', proto, '--dport', str(port), '-j', 'ACCEPT'] + '-m', proto, '--dport', IpTablesManager.port_as_argument(port), '-j', 'ACCEPT'] def create_jump(self): if self.check_mode: @@ -136,10 +146,10 @@ class IpTablesManager(object): # pylint: disable=too-many-instance-attributes else: try: cmd = self.cmd + ['-L', self.jump_rule_chain, '--line-numbers'] - output = check_output(cmd, stderr=subprocess.STDOUT) + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) # break the input rules into rows and columns - input_rules = [s.split() for s in output.split('\n')] + input_rules = [s.split() for s in to_native(output).split('\n')] # Find the last numbered rule last_rule_num = None @@ -155,8 +165,7 @@ class IpTablesManager(object): # pylint: disable=too-many-instance-attributes # Naively assume that if the last row is a REJECT or DROP rule, # then we can insert our rule right before it, otherwise we # assume that we can just append the rule. - if (last_rule_num and last_rule_target - and last_rule_target in ['REJECT', 'DROP']): + if (last_rule_num and last_rule_target and last_rule_target in ['REJECT', 'DROP']): # insert rule cmd = self.cmd + ['-I', self.jump_rule_chain, str(last_rule_num)] @@ -164,7 +173,7 @@ class IpTablesManager(object): # pylint: disable=too-many-instance-attributes # append rule cmd = self.cmd + ['-A', self.jump_rule_chain] cmd += ['-j', self.chain] - output = check_output(cmd, stderr=subprocess.STDOUT) + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) self.changed = True self.output.append(output) self.save() @@ -192,8 +201,7 @@ class IpTablesManager(object): # pylint: disable=too-many-instance-attributes else: try: cmd = self.cmd + ['-N', self.chain] - self.output.append(check_output(cmd, - stderr=subprocess.STDOUT)) + self.output.append(subprocess.check_output(cmd, stderr=subprocess.STDOUT)) self.changed = True self.output.append("Successfully created chain %s" % self.chain) @@ -203,26 +211,26 @@ class IpTablesManager(object): # pylint: disable=too-many-instance-attributes chain=self.chain, msg="Failed to create chain: %s" % self.chain, cmd=ex.cmd, exit_code=ex.returncode, output=ex.output - ) + ) def jump_rule_exists(self): cmd = self.cmd + ['-C', self.jump_rule_chain, '-j', self.chain] - return True if call(cmd) == 0 else False + return True if subprocess.call(cmd) == 0 else False def chain_exists(self): cmd = self.cmd + ['-L', self.chain] - return True if call(cmd) == 0 else False + return True if subprocess.call(cmd) == 0 else False def gen_cmd(self): cmd = 'iptables' if self.ip_version == 'ipv4' else 'ip6tables' return ["/usr/sbin/%s" % cmd] - def gen_save_cmd(self): # pylint: disable=no-self-use + def gen_save_cmd(self): # pylint: disable=no-self-use return ['/usr/libexec/iptables/iptables.init', 'save'] def main(): - module = AnsibleModule( + module = AnsibleModule( # noqa: F405 argument_spec=dict( name=dict(required=True), action=dict(required=True, choices=['add', 'remove', @@ -231,7 +239,7 @@ def main(): create_jump_rule=dict(required=False, type='bool', default=True), jump_rule_chain=dict(required=False, default='INPUT'), protocol=dict(required=False, choices=['tcp', 'udp']), - port=dict(required=False, type='int'), + port=dict(required=False, type='str'), ip_version=dict(required=False, default='ipv4', choices=['ipv4', 'ipv6']), ), @@ -266,8 +274,9 @@ def main(): output=iptables_manager.output) -# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, wrong-import-position # import module snippets -from ansible.module_utils.basic import * +from ansible.module_utils.basic import * # noqa: F403,E402 +from ansible.module_utils._text import to_native # noqa: E402 if __name__ == '__main__': main() diff --git a/roles/os_firewall/meta/main.yml b/roles/os_firewall/meta/main.yml index c93335b7b..dca5fc5ff 100644 --- a/roles/os_firewall/meta/main.yml +++ b/roles/os_firewall/meta/main.yml @@ -4,12 +4,13 @@ galaxy_info: description: os_firewall company: Red Hat, Inc. license: Apache License, Version 2.0 - min_ansible_version: 1.7 + min_ansible_version: 2.2 platforms: - - name: EL - versions: - - 7 + - name: EL + versions: + - 7 categories: - - system + - system +allow_duplicates: yes dependencies: -- { role: openshift_facts } + - role: openshift_facts diff --git a/roles/os_firewall/tasks/firewall/firewalld.yml b/roles/os_firewall/tasks/firewall/firewalld.yml index 5ddca1fc0..1101870be 100644 --- a/roles/os_firewall/tasks/firewall/firewalld.yml +++ b/roles/os_firewall/tasks/firewall/firewalld.yml @@ -1,88 +1,45 @@ --- - name: Install firewalld packages - action: "{{ ansible_pkg_mgr }} name=firewalld state=present" + package: name=firewalld state=present when: not openshift.common.is_containerized | bool - register: install_result - -- name: Check if iptables-services is installed - command: rpm -q iptables-services - register: pkg_check - failed_when: pkg_check.rc > 1 - changed_when: no - name: Ensure iptables services are not enabled - service: + systemd: name: "{{ item }}" state: stopped enabled: no + masked: yes with_items: - - iptables - - ip6tables - when: pkg_check.rc == 0 - -- name: Reload systemd units - command: systemctl daemon-reload - when: install_result | changed - -- name: Determine if firewalld service masked - command: > - systemctl is-enabled firewalld - register: os_firewall_firewalld_masked_output - changed_when: false - failed_when: false - -- name: Unmask firewalld service - command: > - systemctl unmask firewalld - when: os_firewall_firewalld_masked_output.stdout == "masked" + - iptables + - ip6tables + register: task_result + failed_when: "task_result|failed and 'could not' not in task_result.msg|lower" - name: Start and enable firewalld service - service: + systemd: name: firewalld state: started enabled: yes + masked: no + daemon_reload: yes register: result - name: need to pause here, otherwise the firewalld service starting can sometimes cause ssh to fail pause: seconds=10 when: result | changed -- name: Mask iptables services - command: systemctl mask "{{ item }}" - register: result - changed_when: "'iptables' in result.stdout" - with_items: - - iptables - - ip6tables - when: pkg_check.rc == 0 - ignore_errors: yes - -# TODO: Ansible 1.9 will eliminate the need for separate firewalld tasks for -# enabling rules and making them permanent with the immediate flag - name: Add firewalld allow rules firewalld: port: "{{ item.port }}" - permanent: false - state: enabled - with_items: "{{ os_firewall_allow }}" - -- name: Persist firewalld allow rules - firewalld: - port: "{{ item.port }}" permanent: true + immediate: true state: enabled with_items: "{{ os_firewall_allow }}" - name: Remove firewalld allow rules firewalld: port: "{{ item.port }}" - permanent: false - state: disabled - with_items: "{{ os_firewall_deny }}" - -- name: Persist removal of firewalld allow rules - firewalld: - port: "{{ item.port }}" permanent: true + immediate: true state: disabled with_items: "{{ os_firewall_deny }}" diff --git a/roles/os_firewall/tasks/firewall/iptables.yml b/roles/os_firewall/tasks/firewall/iptables.yml index 470d4f4f9..930b32cf2 100644 --- a/roles/os_firewall/tasks/firewall/iptables.yml +++ b/roles/os_firewall/tasks/firewall/iptables.yml @@ -1,64 +1,28 @@ --- -- name: Check if firewalld is installed - command: rpm -q firewalld - args: - # Disables the following warning: - # Consider using yum, dnf or zypper module rather than running rpm - warn: no - register: pkg_check - failed_when: pkg_check.rc > 1 - changed_when: no - name: Ensure firewalld service is not enabled - service: + systemd: name: firewalld state: stopped enabled: no - when: pkg_check.rc == 0 - -# TODO: submit PR upstream to add mask/unmask to service module -- name: Mask firewalld service - command: systemctl mask firewalld - register: result - changed_when: "'firewalld' in result.stdout" - when: pkg_check.rc == 0 - ignore_errors: yes + masked: yes + register: task_result + failed_when: "task_result|failed and 'could not' not in task_result.msg|lower" - name: Install iptables packages - action: "{{ ansible_pkg_mgr }} name={{ item }} state=present" + package: name={{ item }} state=present with_items: - - iptables - - iptables-services - register: install_result + - iptables + - iptables-services when: not openshift.common.is_atomic | bool -- name: Reload systemd units - command: systemctl daemon-reload - when: install_result | changed - -- name: Determine if iptables service masked - command: > - systemctl is-enabled {{ item }} - with_items: - - iptables - - ip6tables - register: os_firewall_iptables_masked_output - changed_when: false - failed_when: false - -- name: Unmask iptables service - command: > - systemctl unmask {{ item }} - with_items: - - iptables - - ip6tables - when: "'masked' in os_firewall_iptables_masked_output.results | map(attribute='stdout')" - - name: Start and enable iptables service - service: + systemd: name: iptables state: started enabled: yes + masked: no + daemon_reload: yes register: result - name: need to pause here, otherwise the iptables service starting can sometimes cause ssh to fail diff --git a/roles/os_firewall/tasks/main.yml b/roles/os_firewall/tasks/main.yml index 076e5e311..20efe5b0d 100644 --- a/roles/os_firewall/tasks/main.yml +++ b/roles/os_firewall/tasks/main.yml @@ -1,4 +1,10 @@ --- +- name: Assert - Do not use firewalld on Atomic Host + assert: + that: not os_firewall_use_firewalld | bool + msg: "Firewalld is not supported on Atomic Host" + when: openshift.common.is_atomic | bool + - include: firewall/firewalld.yml when: os_firewall_enabled | bool and os_firewall_use_firewalld | bool |