diff --git a/README.md b/README.md index 7671fff..614ce5c 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,20 @@ Installs and configures the Cockpit Web Console for distributions that support i - RHEL/CentOS 7.x depend on the Extras repository being enabled. - Recommended to use [`linux-system-roles.firewall`](https://github.com/linux-system-roles/firewall/) to make the Web Console available remotely. + - The role requires the `firewall` role and the `selinux` role from the + `fedora.linux_system_roles` collection, if `cockpit_manage_firewall` + and `cockpit_manage_selinux` is set to yes, respectively. + Please see also `cockpit_manage_firewall` and `cockpit_manage_selinux` + in [`Role Variables`](#role-variables). + + If `cockpit` is a role from the `fedora.linux_system_roles` collection + or from the Fedora RPM package, the requirement is already satisfied. + + Otherwise, please run the following command line to install the collection. + ``` + ansible-galaxy collection install -r meta/collection-requirements.yml + ``` + ## Role Variables Available variables per distribution are listed below, along with default values (see `defaults/main.yml`): @@ -81,17 +95,36 @@ Configure settings in the /etc/cockpit/cockpit.conf file. See [`man cockpit.con cockpit_port: 9090 Cockpit runs on port 9090 by default. You can change the port with this option. -Note that the default SELinux policy does not allow Cockpit to listen to anything else than port 9090, so you need to allow that first, with e.g. + cockpit_manage_firewall: no +Boolean variable to control the `cockpit` firewall service with the `firewall` role. +If the variable is set to `no`, the `cockpit` role does not manage the firewall. +Default to `no`. + +NOTE: `cockpit_manage_firewall` is limited to *adding* ports. +It cannot be used for *removing* ports. +If you want to remove ports, you will need to use the firewall system +role directly. - semanage port -m -t websm_port_t -p tcp 443 +NOTE: This functionality is supported only when the managed host's `os_family` +is `RedHat`. -for ports that are already defined in the SELinux policy, such as 443, or + cockpit_manage_selinux: no +Boolean flag allowing to configure selinux using the selinux role. +The default SELinux policy does not allow Cockpit to listen to anything else +than port 9090. If you change the port, enable this to use the selinux role +to set the correct port permissions (websm_port_t). +If the variable is set to no, the `cockpit` role does not manage the +SELinux permissions of the cockpit port. - semanage port -a -t websm_port_t -p tcp 9999 +NOTE: `cockpit_manage_selinux` is limited to *adding* policy. +It cannot be used for *removing* policy. +If you want to remove policy, you will need to use the selinux system +role directly. -otherwise. +NOTE: This functionality is supported only when the managed host's `os_family` +is `RedHat`. -See the [Cockpit guide](https://cockpit-project.org/guide/latest/listen.html#listen-systemd) for details. +See also the [Cockpit guide](https://cockpit-project.org/guide/latest/listen.html#listen-systemd) for details. ## Certificate setup diff --git a/defaults/main.yml b/defaults/main.yml index d5f59d3..5fccdb0 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -14,3 +14,12 @@ __cockpit_daemon: cockpit.socket # __cockpit_packages_default set in vars/* # __cockpit_packages_full set in vars/* # __cockpit_packages_minimal set in vars/* + +# Cockpit runs on port 9090 by default. +cockpit_port: null + +# If yes, manage the cockpit ports using the firewall role. +cockpit_manage_firewall: no + +# If yes, manage the cockpit ports using the selinux role. +cockpit_manage_selinux: no diff --git a/meta/collection-requirements.yml b/meta/collection-requirements.yml new file mode 100644 index 0000000..6da9740 --- /dev/null +++ b/meta/collection-requirements.yml @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT +collections: + - fedora.linux_system_roles diff --git a/tasks/firewall.yml b/tasks/firewall.yml new file mode 100644 index 0000000..7336432 --- /dev/null +++ b/tasks/firewall.yml @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: MIT +--- +- name: Ensure the cockpit service is enabled + include_role: + name: fedora.linux_system_roles.firewall + vars: + _cockpit_port: "{{ cockpit_port if cockpit_port is not none else 9090 }}" + _cockpit_port_proto: "{{ _cockpit_port }}/tcp" + firewall: "{{ [{'service': 'cockpit', 'state': 'enabled'}] + if (_cockpit_port | int) == 9090 else + [{'port': _cockpit_port_proto, 'state': 'enabled'}] }}" + when: + - cockpit_manage_firewall | bool + - ansible_facts['os_family'] == 'RedHat' diff --git a/tasks/main.yml b/tasks/main.yml index 6cb37e2..aee7476 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -24,13 +24,19 @@ - "setup-{{ ansible_pkg_mgr }}.yml" - "setup-default.yml" +- name: Configure firewall + include_tasks: firewall.yml + +- name: Configure selinux + include_tasks: selinux.yml + - name: Create custom port configuration file directory file: path: /etc/systemd/system/cockpit.socket.d/ owner: root group: root state: directory - when: cockpit_port is defined + when: cockpit_port is not none - name: Create custom port configuration file copy: @@ -42,7 +48,7 @@ [Socket] ListenStream= ListenStream={{ cockpit_port }} - when: cockpit_port is defined + when: cockpit_port is not none notify: - reload systemd - restart cockpit @@ -51,7 +57,7 @@ file: path: /etc/systemd/system/cockpit.socket.d/listen.conf state: absent - when: cockpit_port is not defined + when: cockpit_port is none notify: - reload systemd - restart cockpit diff --git a/tasks/selinux.yml b/tasks/selinux.yml new file mode 100644 index 0000000..bd9c519 --- /dev/null +++ b/tasks/selinux.yml @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: MIT +--- +- name: Ensure the service and the ports status with the selinux role + include_role: + name: fedora.linux_system_roles.selinux + vars: + selinux_ports: "{{ [{'ports': cockpit_port, 'proto': 'tcp', + 'setype': 'websm_port_t', + 'state': 'present', 'local': 'true'}] }}" + when: + - cockpit_manage_selinux | bool + - ansible_facts['os_family'] == 'RedHat' + - cockpit_port is not none diff --git a/tests/tasks/check_port.yml b/tests/tasks/check_port.yml new file mode 100644 index 0000000..47cca74 --- /dev/null +++ b/tests/tasks/check_port.yml @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: MIT +--- +- block: + - block: + - name: Check firewall port status when cockpit_manage_firewall is yes + command: firewall-cmd --list-service + register: _result + failed_when: "'cockpit' not in _result.stdout" + changed_when: false + when: + - _cockpit_port | int == 9090 + + - name: Check firewall port status when cockpit_manage_firewall is yes + command: firewall-cmd --list-port + register: _result + failed_when: "'{{ _cockpit_port }}/tcp' not in _result.stdout" + changed_when: false + when: + - _cockpit_port | int != 9090 + when: + - cockpit_manage_firewall | bool + + - block: + - name: Install SELinux tools + include_tasks: install_selinux_tools.yml + + - name: Check associated selinux ports when cockpit_manage_selinux is yes + shell: |- + set -euo pipefail + semanage port --list | egrep "websm_port_t *tcp" | grep "{{ _cockpit_port }}" + changed_when: false + when: cockpit_manage_selinux | bool + vars: + _cockpit_port: "{{ cockpit_port if cockpit_port is not none else 9090 }}" + when: + - ansible_facts['os_family'] == 'RedHat' diff --git a/tests/tasks/install_selinux_tools.yml b/tests/tasks/install_selinux_tools.yml new file mode 100644 index 0000000..cbd4da5 --- /dev/null +++ b/tests/tasks/install_selinux_tools.yml @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: MIT +--- +- name: Install SELinux python2 tools + package: + name: + - libselinux-python + - policycoreutils-python + state: present + when: ( ansible_python_version is version('3', '<') and + ansible_distribution in ["Fedora", "CentOS", "RedHat", "Rocky"] ) + +- name: Install SELinux python3 tools + package: + name: + - libselinux-python3 + - policycoreutils-python3 + state: present + when: ( ansible_python_version is version('3', '>=') and + ansible_distribution in ["Fedora", "CentOS", "RedHat", "Rocky"] ) + +- name: Install SELinux tool semanage + package: + name: + - policycoreutils-python-utils + state: present + when: ansible_distribution == "Fedora" or + ( ansible_distribution_major_version | int > 7 and + ansible_distribution in ["CentOS", "RedHat", "Rocky"] ) diff --git a/tests/tests_config.yml b/tests/tests_config.yml index e3d0f63..ca1b893 100644 --- a/tests/tests_config.yml +++ b/tests/tests_config.yml @@ -12,6 +12,9 @@ LoginTitle: "hello world" Session: IdleTimeout: 60 + cockpit_manage_firewall: no + cockpit_manage_selinux: yes + public: true tasks: - name: tests @@ -58,5 +61,8 @@ command: diff -u /run/cockpit.conf.expected /etc/cockpit/cockpit.conf changed_when: false + - name: test - ensure cockpit_port is configured for firewall and selinux + include_tasks: tasks/check_port.yml + always: - include_tasks: tasks/cleanup.yml diff --git a/tests/tests_packages_full.yml b/tests/tests_packages_full.yml index 9353fae..ebcfd53 100644 --- a/tests/tests_packages_full.yml +++ b/tests/tests_packages_full.yml @@ -6,8 +6,11 @@ block: - include_role: name: linux-system-roles.cockpit + public: true vars: cockpit_packages: full + cockpit_manage_firewall: yes + cockpit_manage_selinux: no - meta: flush_handlers @@ -37,5 +40,8 @@ msg: cockpit-doc is not installed when: "'cockpit-doc' not in ansible_facts.packages" + - name: test - ensure cockpit_port is configured for firewall and selinux + include_tasks: tasks/check_port.yml + always: - include_tasks: tasks/cleanup.yml diff --git a/tests/tests_port.yml b/tests/tests_port.yml index 15c432f..761e704 100644 --- a/tests/tests_port.yml +++ b/tests/tests_port.yml @@ -5,32 +5,8 @@ tasks: - name: tests block: - - name: Install SELinux python2 tools - package: - name: - - libselinux-python - - policycoreutils-python - state: present - when: ( ansible_python_version is version('3', '<') and - ansible_distribution in ["Fedora", "CentOS", "RedHat", "Rocky"] ) - - - name: Install SELinux python3 tools - package: - name: - - libselinux-python3 - - policycoreutils-python3 - state: present - when: ( ansible_python_version is version('3', '>=') and - ansible_distribution in ["Fedora", "CentOS", "RedHat", "Rocky"] ) - - - name: Install SELinux tool semanage - package: - name: - - policycoreutils-python-utils - state: present - when: ansible_distribution == "Fedora" or - ( ansible_distribution_major_version | int > 7 and - ansible_distribution in ["CentOS", "RedHat", "Rocky"] ) + - name: Install SELinux tools + include_tasks: tasks/install_selinux_tools.yml - name: Allow cockpit to own customized port in SELinux shell: if selinuxenabled; then semanage port -m -t websm_port_t -p tcp 443; fi diff --git a/tests/tests_port2.yml b/tests/tests_port2.yml new file mode 100644 index 0000000..0b1d8c9 --- /dev/null +++ b/tests/tests_port2.yml @@ -0,0 +1,46 @@ +--- +- name: Test cockpit_* role options + hosts: all + gather_facts: true + tasks: + - name: tests + block: + - name: Run cockpit role + include_role: + name: linux-system-roles.cockpit + public: true + vars: + cockpit_manage_firewall: yes + cockpit_manage_selinux: yes + cockpit_packages: minimal + cockpit_port: 443 + + - meta: flush_handlers + + - name: test - cockpit works on customized port + get_url: + dest: /run/out + url: https://localhost + validate_certs: no + + - name: test - HTTP response is something sensible + command: grep 'id="login-user-input"' /run/out + + - name: test - cockpit does not listen on port 9090 + get_url: + dest: /run/out + url: https://localhost:9090 + validate_certs: no + register: result + failed_when: result is succeeded + + - name: test - ensure cockpit_port is configured for firewall + include_tasks: tasks/check_port.yml + + - name: test - clean up output file + file: + path: /run/out + state: absent + + always: + - include_tasks: tasks/cleanup.yml