leapp-repository/0041-Check-no-new-unexpected-keys-were-installed-during-t.patch

185 lines
6.6 KiB
Diff
Raw Normal View History

From 930758e269111190f1e5689e75d552d896adab67 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Tue, 4 Jul 2023 18:22:49 +0200
Subject: [PATCH 41/41] Check no new unexpected keys were installed during the
upgrade
Petr Stodulka:
* some refactoring
* added added error logging
* replace the hard error stop by post upgrade report
We do not want to interrupt the upgrade process after the
DNF transaction execution
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
---
.../common/actors/gpgpubkeycheck/actor.py | 23 ++++
.../libraries/gpgpubkeycheck.py | 124 ++++++++++++++++++
2 files changed, 147 insertions(+)
create mode 100644 repos/system_upgrade/common/actors/gpgpubkeycheck/actor.py
create mode 100644 repos/system_upgrade/common/actors/gpgpubkeycheck/libraries/gpgpubkeycheck.py
diff --git a/repos/system_upgrade/common/actors/gpgpubkeycheck/actor.py b/repos/system_upgrade/common/actors/gpgpubkeycheck/actor.py
new file mode 100644
index 00000000..3d11de38
--- /dev/null
+++ b/repos/system_upgrade/common/actors/gpgpubkeycheck/actor.py
@@ -0,0 +1,23 @@
+from leapp.actors import Actor
+from leapp.libraries.actor import gpgpubkeycheck
+from leapp.models import TrustedGpgKeys
+from leapp.reporting import Report
+from leapp.tags import ApplicationsPhaseTag, IPUWorkflowTag
+
+
+class GpgPubkeyCheck(Actor):
+ """
+ Checks no unexpected GPG keys were installed during the upgrade.
+
+ This should be mostly sanity check and this should not happen
+ unless something went very wrong, regardless the gpgcheck was
+ used (default) or not (with --no-gpgcheck option).
+ """
+
+ name = 'gpg_pubkey_check'
+ consumes = (TrustedGpgKeys,)
+ produces = (Report,)
+ tags = (IPUWorkflowTag, ApplicationsPhaseTag,)
+
+ def process(self):
+ gpgpubkeycheck.process()
diff --git a/repos/system_upgrade/common/actors/gpgpubkeycheck/libraries/gpgpubkeycheck.py b/repos/system_upgrade/common/actors/gpgpubkeycheck/libraries/gpgpubkeycheck.py
new file mode 100644
index 00000000..387c6cef
--- /dev/null
+++ b/repos/system_upgrade/common/actors/gpgpubkeycheck/libraries/gpgpubkeycheck.py
@@ -0,0 +1,124 @@
+from leapp import reporting
+from leapp.libraries.common.gpg import is_nogpgcheck_set
+from leapp.libraries.common.rpms import get_installed_rpms
+from leapp.libraries.stdlib import api
+from leapp.models import TrustedGpgKeys
+
+FMT_LIST_SEPARATOR = '\n - '
+
+
+def _get_installed_fps_tuple():
+ """
+ Return list of tuples (fingerprint, packager).
+ """
+ installed_fps_tuple = []
+ rpms = get_installed_rpms()
+ for rpm in rpms:
+ rpm = rpm.strip()
+ if not rpm:
+ continue
+ try:
+ # NOTE: pgpsig is (none) for 'gpg-pubkey' entries
+ name, version, dummy_release, dummy_epoch, packager, dummy_arch, dummy_pgpsig = rpm.split('|')
+ except ValueError as e:
+ # NOTE: it's seatbelt, but if it happens, seeing loong list of errors
+ # will let us know earlier that we missed something really
+ api.current_logger().error('Cannot perform the check of installed GPG keys after the upgrade.')
+ api.current_logger().error('Cannot parse rpm output: {}'.format(e))
+ continue
+ if name != 'gpg-pubkey':
+ continue
+ installed_fps_tuple.append((version, packager))
+ return installed_fps_tuple
+
+
+def _report_cannot_check_keys(installed_fps):
+ # NOTE: in this case, it's expected there will be always some GPG keys present
+ summary = (
+ 'Cannot perform the check of GPG keys installed in the RPM DB'
+ ' due to missing facts (TrustedGpgKeys) supposed to be generated'
+ ' in the start of the upgrade process on the original system.'
+ ' Unexpected unexpected installed GPG keys could be e.g. a mark of'
+ ' a malicious attempt to hijack the upgrade process.'
+ ' The list of all GPG keys in RPM DB:{sep}{key_list}'
+ .format(
+ sep=FMT_LIST_SEPARATOR,
+ key_list=FMT_LIST_SEPARATOR.join(installed_fps)
+ )
+ )
+ hint = (
+ 'Verify the installed GPG keys are expected.'
+ )
+ groups = [
+ reporting.Groups.POST,
+ reporting.Groups.REPOSITORY,
+ reporting.Groups.SECURITY
+ ]
+ reporting.create_report([
+ reporting.Title('Cannot perform the check of installed GPG keys after the upgrade.'),
+ reporting.Summary(summary),
+ reporting.Severity(reporting.Severity.HIGH),
+ reporting.Groups(groups),
+ reporting.Remediation(hint=hint),
+ ])
+
+
+def _report_unexpected_keys(unexpected_fps):
+ summary = (
+ 'The system contains unexpected GPG keys after upgrade.'
+ ' This can be caused e.g. by a manual intervention'
+ ' or by malicious attempt to hijack the upgrade process.'
+ ' The unexpected keys are the following:'
+ ' {sep}{key_list}'
+ .format(
+ sep=FMT_LIST_SEPARATOR,
+ key_list=FMT_LIST_SEPARATOR.join(unexpected_fps)
+ )
+ )
+ hint = (
+ 'Verify the installed GPG keys are expected.'
+ )
+ groups = [
+ reporting.Groups.POST,
+ reporting.Groups.REPOSITORY,
+ reporting.Groups.SECURITY
+ ]
+ reporting.create_report([
+ reporting.Title('Detected unexpected GPG keys after the upgrade.'),
+ reporting.Summary(summary),
+ reporting.Severity(reporting.Severity.HIGH),
+ reporting.Groups(groups),
+ reporting.Remediation(hint=hint),
+ ])
+
+
+def process():
+ """
+ Verify the system does not have any unexpected gpg keys installed
+
+ If the --no-gpgcheck option is used, this is skipped as we can not
+ guarantee that what was installed came from trusted source
+ """
+
+ if is_nogpgcheck_set():
+ api.current_logger().warning('The --nogpgcheck option is used: Skipping the check of installed GPG keys.')
+ return
+
+ installed_fps_tuple = _get_installed_fps_tuple()
+
+ try:
+ trusted_gpg_keys = next(api.consume(TrustedGpgKeys))
+ except StopIteration:
+ # unexpected (bug) situation; keeping as seatbelt for the security aspect
+ installed_fps = ['{fp}: {packager}'.format(fp=fp, packager=packager) for fp, packager in installed_fps_tuple]
+ _report_cannot_check_keys(installed_fps)
+ return
+
+ trusted_fps = [key.fingerprint for key in trusted_gpg_keys.items]
+ unexpected_fps = []
+ for fp, packager in installed_fps_tuple:
+ if fp not in trusted_fps:
+ unexpected_fps.append('{fp}: {packager}'.format(fp=fp, packager=packager))
+
+ if unexpected_fps:
+ _report_unexpected_keys(unexpected_fps)
--
2.41.0