210 lines
8.2 KiB
Diff
210 lines
8.2 KiB
Diff
From eeb4f99f57c67937ea562fce11fd5607470ae0a6 Mon Sep 17 00:00:00 2001
|
|
From: Petr Stodulka <pstodulk@redhat.com>
|
|
Date: Fri, 22 Apr 2022 00:20:15 +0200
|
|
Subject: [PATCH] [IPU 8 -> 9] Migrate blacklisted CAs (hotfix)
|
|
|
|
Preserve blacklisted certificates during the IPU 8 -> 9
|
|
|
|
Path for the blacklisted certificates has been changed on RHEL 9.
|
|
The original paths on RHEL 8 and older systems have been:
|
|
/etc/pki/ca-trust/source/blacklist/
|
|
/usr/share/pki/ca-trust-source/blacklist/
|
|
However on RHEL 9 the blacklist directory has been renamed to 'blocklist'.
|
|
So the paths are:
|
|
/etc/pki/ca-trust/source/blocklist/
|
|
/usr/share/pki/ca-trust-source/blocklist/
|
|
This actor moves all blacklisted certificates into the expected directories
|
|
and fix symlinks if to point to the new dirs if they originally pointed
|
|
to one of obsoleted dirs.
|
|
|
|
Covered cases:
|
|
- covered situations with missing dirs
|
|
- covered both mentioned blacklist directories
|
|
- update symlinks in case they point to one of obsoleted directories
|
|
- remove obsoleted directories when all files migrated successfully
|
|
- execute /usr/bin/update-ca-trust in the end
|
|
- remove original a blacklist directory in case all discovered files
|
|
inside are migrated successfully
|
|
- print error logs in case of any issues so the upgrade does not
|
|
crash in case of troubles and users could deal with problems
|
|
manually after the upgrade
|
|
|
|
The actor is not covered by unit-tests as it's just a hotfix. Follow
|
|
up works are expected to extend the problem with reports during
|
|
preupgrade phases, improve the test coverage, ....
|
|
|
|
BZ: https://bugzilla.redhat.com/show_bug.cgi?id=2077432
|
|
Followup ticket: CRYPTO-7097
|
|
---
|
|
.../actors/migrateblacklistca/actor.py | 28 ++++++
|
|
.../libraries/migrateblacklistca.py | 89 +++++++++++++++++++
|
|
.../tests/unit_test_migrateblacklistca.py | 25 ++++++
|
|
3 files changed, 142 insertions(+)
|
|
create mode 100644 repos/system_upgrade/el8toel9/actors/migrateblacklistca/actor.py
|
|
create mode 100644 repos/system_upgrade/el8toel9/actors/migrateblacklistca/libraries/migrateblacklistca.py
|
|
create mode 100644 repos/system_upgrade/el8toel9/actors/migrateblacklistca/tests/unit_test_migrateblacklistca.py
|
|
|
|
diff --git a/repos/system_upgrade/el8toel9/actors/migrateblacklistca/actor.py b/repos/system_upgrade/el8toel9/actors/migrateblacklistca/actor.py
|
|
new file mode 100644
|
|
index 00000000..863a0063
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el8toel9/actors/migrateblacklistca/actor.py
|
|
@@ -0,0 +1,28 @@
|
|
+from leapp.actors import Actor
|
|
+from leapp.libraries.actor import migrateblacklistca
|
|
+from leapp.tags import ApplicationsPhaseTag, IPUWorkflowTag
|
|
+
|
|
+
|
|
+class MigrateBlacklistCA(Actor):
|
|
+ """
|
|
+ Preserve blacklisted certificates during the upgrade
|
|
+
|
|
+ Path for the blacklisted certificates has been changed on RHEL 9.
|
|
+ The original paths on RHEL 8 and older systems have been:
|
|
+ /etc/pki/ca-trust/source/blacklist/
|
|
+ /usr/share/pki/ca-trust-source/blacklist/
|
|
+ However on RHEL 9 the blacklist directory has been renamed to 'blocklist'.
|
|
+ So the new paths are:
|
|
+ /etc/pki/ca-trust/source/blocklist/
|
|
+ /usr/share/pki/ca-trust-source/blocklist/
|
|
+ This actor moves all blacklisted certificates into the expected directories
|
|
+ and fix symlinks if needed.
|
|
+ """
|
|
+
|
|
+ name = 'migrate_blacklist_ca'
|
|
+ consumes = ()
|
|
+ produces = ()
|
|
+ tags = (ApplicationsPhaseTag, IPUWorkflowTag)
|
|
+
|
|
+ def process(self):
|
|
+ migrateblacklistca.process()
|
|
diff --git a/repos/system_upgrade/el8toel9/actors/migrateblacklistca/libraries/migrateblacklistca.py b/repos/system_upgrade/el8toel9/actors/migrateblacklistca/libraries/migrateblacklistca.py
|
|
new file mode 100644
|
|
index 00000000..73c9d565
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el8toel9/actors/migrateblacklistca/libraries/migrateblacklistca.py
|
|
@@ -0,0 +1,89 @@
|
|
+import os
|
|
+import shutil
|
|
+
|
|
+from leapp.libraries.stdlib import api, CalledProcessError, run
|
|
+
|
|
+# dict(orig_dir: new_dir)
|
|
+DIRS_CHANGE = {
|
|
+ '/etc/pki/ca-trust/source/blacklist/': '/etc/pki/ca-trust/source/blocklist/',
|
|
+ '/usr/share/pki/ca-trust-source/blacklist/': '/usr/share/pki/ca-trust-source/blocklist/'
|
|
+}
|
|
+
|
|
+
|
|
+def _link_src_path(filepath):
|
|
+ """
|
|
+ Return expected target path for the symlink.
|
|
+
|
|
+ In case the symlink points to one of dirs supposed to be migrated in this
|
|
+ actor, we need to point to the new directory instead.
|
|
+
|
|
+ In case the link points anywhere else, keep the target path as it is.
|
|
+ """
|
|
+ realpath = os.path.realpath(filepath)
|
|
+ for dirname in DIRS_CHANGE:
|
|
+ if realpath.startswith(dirname):
|
|
+ return realpath.replace(dirname, DIRS_CHANGE[dirname])
|
|
+
|
|
+ # it seems we can keep this path
|
|
+ return realpath
|
|
+
|
|
+
|
|
+def _migrate_file(filename, src_basedir):
|
|
+ dst_path = filename.replace(src_basedir, DIRS_CHANGE[src_basedir])
|
|
+ if os.path.exists(dst_path):
|
|
+ api.current_logger().info(
|
|
+ 'Skipping migration of the {} certificate. The target file already exists'
|
|
+ .format(filename)
|
|
+ )
|
|
+ return
|
|
+ os.makedirs(os.path.dirname(dst_path), mode=0o755, exist_ok=True)
|
|
+ if os.path.islink(filename):
|
|
+ # create the new symlink instead of the moving the file
|
|
+ # as the target path could be different as well
|
|
+ link_src_path = _link_src_path(filename)
|
|
+ # TODO: is the broken symlink ok?
|
|
+ os.symlink(link_src_path, dst_path)
|
|
+ os.unlink(filename)
|
|
+ else:
|
|
+ # normal file, just move it
|
|
+ shutil.move(filename, dst_path)
|
|
+
|
|
+
|
|
+def _get_files(dirname):
|
|
+ return run(['find', dirname, '-type', 'f,l'], split=True)['stdout']
|
|
+
|
|
+
|
|
+def process():
|
|
+ for dirname in DIRS_CHANGE:
|
|
+ if not os.path.exists(dirname):
|
|
+ # The directory does not exist; nothing to do here
|
|
+ continue
|
|
+ try:
|
|
+ blacklisted_certs = _get_files(dirname)
|
|
+ except (CalledProcessError, OSError) as e:
|
|
+ # TODO: create post-upgrade report
|
|
+ api.current_logger().error('Cannot get list of files in {}: {}.'.format(dirname, e))
|
|
+ api.current_logger().error('Certificates under {} must be migrated manually.'.format(dirname))
|
|
+ continue
|
|
+ failed_files = []
|
|
+ for filename in blacklisted_certs:
|
|
+ try:
|
|
+ _migrate_file(filename, dirname)
|
|
+ except OSError as e:
|
|
+ api.current_logger().error(
|
|
+ 'Failed migration of blacklisted certificate {}: {}'
|
|
+ .format(filename, e)
|
|
+ )
|
|
+ failed_files.append(filename)
|
|
+ if not failed_files:
|
|
+ # the failed removal is not such a big issue here
|
|
+ # clean the dir if all files have been migrated successfully
|
|
+ shutil.rmtree(dirname, ignore_errors=True)
|
|
+ try:
|
|
+ run(['/usr/bin/update-ca-trust'])
|
|
+ except (CalledProcessError, OSError) as e:
|
|
+ api.current_logger().error(
|
|
+ 'Cannot update CA trust on the system.'
|
|
+ ' It needs to be done manually after the in-place upgrade.'
|
|
+ ' Reason: {}'.format(e)
|
|
+ )
|
|
diff --git a/repos/system_upgrade/el8toel9/actors/migrateblacklistca/tests/unit_test_migrateblacklistca.py b/repos/system_upgrade/el8toel9/actors/migrateblacklistca/tests/unit_test_migrateblacklistca.py
|
|
new file mode 100644
|
|
index 00000000..970dcb97
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el8toel9/actors/migrateblacklistca/tests/unit_test_migrateblacklistca.py
|
|
@@ -0,0 +1,25 @@
|
|
+import os
|
|
+
|
|
+from leapp.libraries.actor import migrateblacklistca
|
|
+from leapp.libraries.common.testutils import CurrentActorMocked
|
|
+from leapp.libraries.stdlib import api
|
|
+
|
|
+
|
|
+class MockedGetFiles():
|
|
+ def __init__(self):
|
|
+ self.called = 0
|
|
+
|
|
+ def __call__(self):
|
|
+ self.called += 1
|
|
+ return []
|
|
+
|
|
+
|
|
+def test_no_dirs_exist(monkeypatch):
|
|
+ mocked_files = MockedGetFiles()
|
|
+ monkeypatch.setattr(os.path, 'exists', lambda dummy: False)
|
|
+ monkeypatch.setattr(migrateblacklistca, '_get_files', mocked_files)
|
|
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked())
|
|
+ # this is bad mock, but we want to be sure that update-ca-trust is not
|
|
+ # called on the testing machine
|
|
+ monkeypatch.setattr(migrateblacklistca, 'run', lambda dummy: dummy)
|
|
+ assert not mocked_files.called
|
|
--
|
|
2.35.1
|
|
|