forked from rpms/leapp-repository
185 lines
6.6 KiB
Diff
185 lines
6.6 KiB
Diff
|
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
|
||
|
|