From d360d7f600d2c22ecefb4904f5d49ca13c0cc294 Mon Sep 17 00:00:00 2001 From: Petr Stodulka Date: Fri, 10 Nov 2023 10:16:05 +0100 Subject: [PATCH] squash! Check no new unexpected keys were installed during the upgrade * 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 --- .../libraries/gpgpubkeycheck.py | 138 ++++++++++++------ 1 file changed, 97 insertions(+), 41 deletions(-) diff --git a/repos/system_upgrade/common/actors/gpgpubkeycheck/libraries/gpgpubkeycheck.py b/repos/system_upgrade/common/actors/gpgpubkeycheck/libraries/gpgpubkeycheck.py index 873b05a551..387c6cefb8 100644 --- a/repos/system_upgrade/common/actors/gpgpubkeycheck/libraries/gpgpubkeycheck.py +++ b/repos/system_upgrade/common/actors/gpgpubkeycheck/libraries/gpgpubkeycheck.py @@ -1,6 +1,5 @@ from leapp import reporting -from leapp.exceptions import StopActorExecutionError -from leapp.libraries.common.gpg import get_path_to_gpg_certs, the_nogpgcheck_option_used +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 @@ -8,6 +7,91 @@ 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 @@ -16,53 +100,25 @@ def process(): guarantee that what was installed came from trusted source """ - if the_nogpgcheck_option_used(): - api.current_logger().warning('The --nogpgcheck option is used: Checking keys does not make sense.') + 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: - raise StopActorExecutionError( - 'Could not check for valid GPG keys', details={'details': 'No TrustedGpgKeys facts'} - ) + # 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 = list() - - rpms = get_installed_rpms() - for rpm in rpms: - rpm = rpm.strip() - if not rpm: - continue - name, version, _, _, packager, _, _ = rpm.split('|') - if name != 'gpg-pubkey': - continue - fp = version + 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: - summary = ( - 'The system contains unexpected GPG keys after upgrade. This can be caused by some manual intervention' - ' or by malicious attempt to hijack the installation 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 keys are expected. If so, make sure they are included in {} directory.' - .format(get_path_to_gpg_certs()) - ) - groups = [reporting.Groups.REPOSITORY, reporting.Groups.SECURITY] - reporting.create_report( - [ - reporting.Title('Unexpected GPG keys found after installation'), - reporting.Summary(summary), - reporting.Severity(reporting.Severity.HIGH), - reporting.Groups(groups), - reporting.Remediation(hint=hint), - ] - ) + _report_unexpected_keys(unexpected_fps)