Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the firewall role and the selinux role from the cockpit role #76

Merged
merged 3 commits into from
Oct 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 39 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`):
Expand Down Expand Up @@ -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

Expand Down
9 changes: 9 additions & 0 deletions defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 3 additions & 0 deletions meta/collection-requirements.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: MIT
collections:
- fedora.linux_system_roles
14 changes: 14 additions & 0 deletions tasks/firewall.yml
Original file line number Diff line number Diff line change
@@ -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'
12 changes: 9 additions & 3 deletions tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Expand All @@ -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
Expand Down
13 changes: 13 additions & 0 deletions tasks/selinux.yml
Original file line number Diff line number Diff line change
@@ -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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add an additional condition that cockpit_port is defined (and remove that from line 7), so that this isn't even invoked when the port doesn't get customized (the common case). Avoids traps and is faster.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm - since cockpit_port is part of the public api of the role, it should be defined in defaults/main.yml as null - so check for cockpit_port is not none (null in YAML == none in Jinja)

Copy link
Contributor Author

@nhosoi nhosoi Sep 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm - since cockpit_port is part of the public api of the role, it should be defined in defaults/main.yml as null - so check for cockpit_port is not none (null in YAML == none in Jinja)

@richm, @martinpitt, README.md describes cockpit_port as follows.

    cockpit_port: 9090
Cockpit runs on port 9090 by default. You can change the port with this option.

This means, it should be defined as 9090 in defaults/main.yml?

We should distinguish the value was set by customers or not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm - since cockpit_port is part of the public api of the role, it should be defined in defaults/main.yml as null - so check for cockpit_port is not none (null in YAML == none in Jinja)

Is it ok for me to make this change in this pr?

Yes, please.

- ansible_facts['os_family'] == 'RedHat'
- cockpit_port is not none
36 changes: 36 additions & 0 deletions tests/tasks/check_port.yml
Original file line number Diff line number Diff line change
@@ -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'
28 changes: 28 additions & 0 deletions tests/tasks/install_selinux_tools.yml
Original file line number Diff line number Diff line change
@@ -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"] )
6 changes: 6 additions & 0 deletions tests/tests_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
LoginTitle: "hello world"
Session:
IdleTimeout: 60
cockpit_manage_firewall: no
cockpit_manage_selinux: yes
public: true

tasks:
- name: tests
Expand Down Expand Up @@ -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
6 changes: 6 additions & 0 deletions tests/tests_packages_full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
28 changes: 2 additions & 26 deletions tests/tests_port.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
46 changes: 46 additions & 0 deletions tests/tests_port2.yml
Original file line number Diff line number Diff line change
@@ -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