diff --git a/CHANGELOG.md b/CHANGELOG.md index 3222449c6..6bf9ebec3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -**Highlights:** Apache no longer loads `mod_info`, which served the complete configuration including other modules' credentials. A broken PHP-FPM configuration aborts the run instead of taking the service down on the restart. Sudo rules deployed by `freeipa_server` can carry their commands again. The Bitwarden lookup can be told to abort instead of silently generating a new password, for runs against hosts whose credentials must already exist. The Grafana graph configuration for the Monitoring Plugins is no longer deployed on every ordinary run and has to be requested explicitly by its tag. +**Highlights:** On RHEL 8, a MariaDB package upgrade no longer cuts applications on the same host off from their database. Apache no longer loads `mod_info`, which served the complete configuration including other modules' credentials. A broken PHP-FPM configuration aborts the run instead of taking the service down on the restart. Sudo rules deployed by `freeipa_server` can carry their commands again. The Bitwarden lookup can be told to abort instead of silently generating a new password, for runs against hosts whose credentials must already exist. The Grafana graph configuration for the Monitoring Plugins is no longer deployed on every ordinary run and has to be requested explicitly by its tag. ### Breaking Changes @@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +* **role:mariadb_server**: On RHEL 8, MariaDB keeps its own SELinux confinement after a package upgrade, by installing `mysql-selinux` the way the MariaDB packages already do on RHEL 9 and 10. Without it, applications on the same host lose their database connection with `Permission denied` as of MariaDB 11.4.13 and 11.8.9. * **playbook:icingaweb2, playbook:setup_icinga2_master, role:icingaweb2** update `icingaweb2` dependent vars to ensure php.ini value `post_max_size` > `upload_max_filesize` by default. * **role:monitoring_plugins**: A source install installs the dependencies of the Linuxfabrik library, so checks that speak HTTP, MySQL, SMB or WinRM no longer report `Python module "httpx" is not installed` and its equivalents. * **role:monitoring_plugins**: A source install deploys the event plugins, which only the rpm/deb package used to ship. diff --git a/extensions/molecule/setup_nextcloud/verify.yml b/extensions/molecule/setup_nextcloud/verify.yml index 0c1ebd7d3..7735e45cd 100644 --- a/extensions/molecule/setup_nextcloud/verify.yml +++ b/extensions/molecule/setup_nextcloud/verify.yml @@ -36,3 +36,40 @@ that: - '(__molecule__nextcloud_statusphp_result["content"] | from_json)["installed"] | bool' fail_msg: 'status.php did not report installed. response: {{ __molecule__nextcloud_statusphp_result["content"] | d("") }}' + + +# The role installs mysql-selinux so mariadbd gets `mysqld_exec_t` (MDEV-30520). Assert the domain +# of the running process, not the label on the file: only that tells `mysqld_t` apart from +# `initrc_t` and the `unconfined_service_t` that used to mask a missing label. +- name: 'Verify mariadbd runs in the mysqld_t SELinux domain' + hosts: 'systems_under_test' + gather_facts: true + become: true + tasks: + + - name: 'ps -o label= -C mariadbd' + ansible.builtin.command: 'ps -o label= -C mariadbd' + register: '__molecule__mariadbd_label_result' + changed_when: false + # ps exits 1 when no process matches, which would otherwise fail the task with a bare rc=1 + # and no indication of what is wrong. The assert below turns it into a sentence. + failed_when: '__molecule__mariadbd_label_result["rc"] not in [0, 1]' + when: + - 'ansible_facts["os_family"] == "RedHat"' + - 'ansible_facts["selinux"]["status"] != "disabled"' + + - name: 'Assert that mariadbd is running' + ansible.builtin.assert: + that: + - '__molecule__mariadbd_label_result["rc"] == 0' + fail_msg: 'No mariadbd process on {{ inventory_hostname }}.' + when: + - '__molecule__mariadbd_label_result is not skipped' + + - name: 'Assert mariadbd transitioned into mysqld_t' + ansible.builtin.assert: + that: + - '"mysqld_t" in __molecule__mariadbd_label_result["stdout"]' + fail_msg: 'mariadbd runs as "{{ __molecule__mariadbd_label_result["stdout"] | trim }}" instead of mysqld_t, so the mysqld_exec_t label on the binary is missing.' + when: + - '__molecule__mariadbd_label_result is not skipped' diff --git a/roles/mariadb_server/tasks/main.yml b/roles/mariadb_server/tasks/main.yml index 3d8410935..2ff976870 100644 --- a/roles/mariadb_server/tasks/main.yml +++ b/roles/mariadb_server/tasks/main.yml @@ -220,19 +220,29 @@ - 'ansible_facts["os_family"] == "RedHat"' - 'ansible_facts["selinux"]["status"] != "disabled"' - # The unit drop-in's `ExecStartPre=-/bin/chcon -t mysqld_exec_t /usr/sbin/mariadbd` workaround for MDEV-30520 cannot relabel the binary on EL10+, where the packaged mariadb.service applies `ProtectSystem` that mounts /usr read-only inside the service sandbox. Set the label persistently here instead. Use `/usr/bin/mariadbd` because SELinux has an equivalency rule `/usr/sbin /usr/bin` (UsrMerge) and `semanage fcontext` rejects the equivalent path. - - name: 'semanage fcontext --add --type mysqld_exec_t /usr/bin/mariadbd' - community.general.sefcontext: - setype: 'mysqld_exec_t' - target: '/usr/bin/mariadbd' + # mysql-selinux ships the file contexts for the `mariadbd` binary names (MDEV-30520); without it + # the binary keeps `bin_t` and never reaches `mysqld_t`. Since 11.4.13 / 11.8.9 that is no longer + # cosmetic: systemd execs `/bin/sh` (MDEV-40629), so an unlabeled binary lands in `initrc_t` + # instead of `unconfined_service_t` and `httpd_t` clients lose the socket. The MariaDB packages + # depend on it on EL9 and EL10, but not on EL8. Installed everywhere anyway: it overrides the + # distro `mysql` module (priority 200 over 100) and tracks the upstream packages we deploy. + - name: 'Install mysql-selinux' + ansible.builtin.package: + name: + - 'mysql-selinux' state: 'present' - register: '__mariadb_server__mariadbd_fcontext_result' when: - 'ansible_facts["os_family"] == "RedHat"' - 'ansible_facts["selinux"]["status"] != "disabled"' + # Galera excluded: in `mysqld_t` the donor's mariabackup cannot reach the local socket and + # SST fails with `Errcode: 13`. Note this only takes effect on EL8. On EL9 and EL10 the + # MariaDB packages depend on mysql-selinux, so it is installed and the binary labeled no + # matter what this role does, and Galera nodes run confined there either way. Tracked in + # https://github.com/Linuxfabrik/lfops/issues/328. - 'mariadb_server__cnf_wsrep_on is false' notify: 'mariadb_server: systemctl restart mariadb' + # relabel the mariadbd binary that is already on disk - name: 'restorecon -Fv /usr/sbin/mariadbd' ansible.builtin.command: 'restorecon -Fv /usr/sbin/mariadbd' register: '__mariadb_server__mariadbd_restorecon_result' diff --git a/roles/mariadb_server/templates/etc/systemd/system/mariadb.service.d/socket-selinux-workaround.conf.j2 b/roles/mariadb_server/templates/etc/systemd/system/mariadb.service.d/socket-selinux-workaround.conf.j2 index f32b7063b..1dde8ee1b 100644 --- a/roles/mariadb_server/templates/etc/systemd/system/mariadb.service.d/socket-selinux-workaround.conf.j2 +++ b/roles/mariadb_server/templates/etc/systemd/system/mariadb.service.d/socket-selinux-workaround.conf.j2 @@ -1,21 +1,16 @@ # {{ ansible_managed }} -# 2024103101 +# 2026082601 -[Service] -{# changing the context of mariadbd does not seem to work with galera. -`WSREP: Failed to start mysqld for wsrep recovery: '... [Warning] Can't create test file '/var/lib/mysql/example.com.lower-test' (Errcode: 13 "Permission denied")` -and `/usr/sbin/mariadbd: Cannot change uid/gid (errno: 1)` -during systemctl start, causes the mariadb.service to fail #} -{% if mariadb_server__cnf_wsrep_on is false %} -ExecStartPre=-/bin/chcon -t mysqld_exec_t /usr/sbin/mariadbd -# SELinux incorrectly labeled mariadbd (see https://jira.mariadb.org/browse/MDEV-30520) -# The bug is present in the MariaDB Repo (here, SELinux rules are missing in the SELinux database), not at Red Hat. - -# ls -Z /usr/sbin/mariadbd -# Wrong: system_u:object_r:bin_t:s0 /usr/sbin/mariadbd -# Correct: system_u:object_r:mysqld_exec_t:s0 /usr/sbin/mariadbd -{% endif %} +# mariadbd is labeled mysqld_exec_t by the role (MDEV-30520), not from here: ProtectSystem mounts +# /usr read-only inside the service sandbox, so a chcon against the binary always fails. +# +# The socket below is a different matter. Once mariadbd actually runs in mysqld_t, the policy +# labels it without help, through `type_transition mysqld_t mysqld_db_t:sock_file +# mysqld_var_run_t` in the base policy of RHEL 8, 9 and 10. This line stays for the hosts where +# that does not apply: Galera nodes, which the role deliberately leaves unlabeled, and a socket +# configured outside both the datadir and /run. Elsewhere it relabels to what is already there. +[Service] ExecStartPost=-/bin/chcon -t mysqld_var_run_t {{ mariadb_server__cnf_socket__combined_var }} # This is a workaround for https://jira.mariadb.org/browse/MDEV-24941. This only occurs when using the official MariaDB Repository. # After restarting the mariadb service, the socket /var/lib/mysql/mysql.sock has the mysqld_db_t SELinux file type, instead of mysqld_var_run_t