Skip to content

Commit

Permalink
Add actors for OpenSSL conf and IBMCA
Browse files Browse the repository at this point in the history
* The openssl-ibmca needs to be reconfigured manually after the upgrade.
  Report it to the user if the package is installed.

* The openssl configuration file (/etc/pki/tls/openssl.cnf) is not
  100% compatible between major verions of RHEL due to different
  versions of OpenSSL. Also the configuration is supposed to be
  done via system wide crypto policies instead, so it's expected
  to not modify this file anymore. If the content of the file has
  been modified, report to user what will happen during the upgrade
  and what they should do after it.

* If the openssl config file is modified (rpm -Vf <file>) and
  *.rpmnew file exists, back up the file with .leappsave suffix
  and replace it by the *.rpmsave one.
  • Loading branch information
pirat89 committed Oct 24, 2023
1 parent 87d1ce7 commit ae3a2b3
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from leapp.actors import Actor
from leapp.libraries.actor import checkopensslconf
from leapp.models import InstalledRedHatSignedRPM, Report, TrackedSourceFilesInfo
from leapp.tags import IPUWorkflowTag, ChecksPhaseTag


class CheckOpenSSLConf(Actor):
"""
Check whether the openssl configuration and openssl-IBMCA.
See the report messages for more details. The summary is that since RHEL 8
it's expected to configure OpenSSL via crypto policies. Also, OpenSSL has
different versions between major versions of RHEL:
* RHEL 7: 1.0,
* RHEL 8: 1.1,
* RHEL 9: 3.0
So OpenSSL configuration from older system does not have to be 100%
compatible with the new system. In some cases, the old configuration could
make the system inaccessible remotely. So new approach is to ensure the
upgraded system will use always new default /etc/pki/tls/openssl.cnf
configuration file (the original one will be backed up if modified by user).
Similar for OpenSSL-IBMCA, when it's expected to configure it again on
each newer system.
"""

name = 'check_openssl_conf'
consumes = (InstalledRedHatSignedRPM, TrackedSourceFilesInfo)
produces = (Report,)
tags = (IPUWorkflowTag, ChecksPhaseTag)

def process(self):
checkopensslconf.process()
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
from leapp import reporting
from leapp.models import InstalledRedHatSignedRPM, TrackedSourceFilesInfo
from leapp.libraries.common.config import architecture, version
from leapp.libraries.common.rpms import has_package
from leapp.libraries.stdlib import api

DEFAULT_OPENSSL_CONF = '/etc/pki/tls/openssl.cnf'


def check_ibmca():
if not architecture.matches_architecture(architecture.ARCH_S390X):
# not needed check really, but keeping it to make it clear
return
if not has_package(InstalledRedHatSignedRPM, 'openssl-ibmca'):
return
# TODO(pstodulk): check with @ksrot whether this is relevant for IPU 8 -> 9 also
# (orig msg was for IPU 7 -> 8 only); engine vs provider?
# https://www.ibm.com/docs/en/linux-on-z?topic=openssl-using-ibmca-provider
summary = (
'The presence of openssl-ibmca package suggests that the system may be configured'
' to use the IBMCA OpenSSL engine.'
' Due to major changes in OpenSSL and libica between RHEL {old} and RHEL {new} it is not'
' possible to migrate OpenSSL configuration files automatically. Therefore,'
' it is necessary to enable IBMCA engine in the OpenSSL config file manually'
' after the system upgrade.'
.format(
old=version.get_source_major_version(),
new=version.get_target_major_version()
)
)

hint = (
'Configure the IBMCA engine manually after the upgrade.'
' Please, be aware that it is not recommended to configure the system default'
' /etc/pki/tls/openssl.cnf. Instead, it is recommended to configure a copy of'
' that file and used this copy only for particular applications that are supposed'
' to utilize the IBMCA engine. The location of the OpenSSL configuration file'
' can be specified using the OPENSSL_CONF environment variable.'
)
# TODO(pstodulk): is there a doc?
# TODO(pstodulk): encryption, security groups?

reporting.create_report([
reporting.Title('Detected possible use of IBMCA in OpenSSL'),
reporting.Summary(summary),
reporting.Remediation(hint=hint),
reporting.Severity(reporting.Severity.MEDIUM),
reporting.Groups([
reporting.Groups.POST,
reporting.Groups.SECURITY,
reporting.Groups.SERVICES
]),
])


def _is_openssl_modified():
tracked_files = next(api.consume(TrackedSourceFilesInfo), None)
if not tracked_files:
# unexpected at all, skipping testing, but keeping the log just in case
api.current_logger.warning('The TrackedSourceFilesInfo message is missing! Skipping check of openssl config.')
return False
for finfo in tracked_files.files:
if finfo.path == DEFAULT_OPENSSL_CONF:
return finfo.is_modified
return False


def check_default_openssl():
if not _is_openssl_modified():
return
# TODO(pstodulk): total TODO. sync with dbelyakov
summary = (
''
)
hint = (
'Review the changes after the upgrade and configure the system as needed'
' via crypto policies.'
)
reporting.create_report([
reporting.Title('The /etc/pki/tls/openssl.cnf file will be replaced by the target RHEL default.'),
reporting.Summary(summary),
reporting.Remediation(hint=hint),
reporting.Severity(reporting.Severity.MEDIUM),
reporting.Groups([reporting.Groups.POST, reporting.Groups.SECURITY]),
])


def process():
check_ibmca()
check_default_openssl()
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import pytest

from leapp import reporting
from leapp.libraries.actor import checkopensslconf
from leapp.libraries.common.config import architecture
from leapp.libraries.common.testutils import CurrentActorMocked, logger_mocked, create_report_mocked
from leapp.libraries.stdlib import api
from leapp.models import InstalledRedHatSignedRPM, TrackedSourceFilesInfo


# TODO(pstodulk)
@pytest.mark.parametrize('arch,msgs,ibmca,openssl', (
(architecture.ARCH_S390X, [], False, False),
))
def test_ibmca(monkeypatch, arch, msgs):
monkeypatch.setattr(reporting, "create_report", create_report_mocked())
monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(arch=arch, msgs=msgs))
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from leapp.actors import Actor
from leapp.libraries.actor import migrateopensslconf
from leapp.tags import IPUWorkflowTag, ApplicationsPhaseTag


class MigrateOpenSslConf(Actor):
"""
Enforce the target default configuration file to be used.
If the /etc/pki/tls/openssl.cnf has been modified and openssl.cnf.rpmnew
file is created, backup the original one and replace it by the new default.
tl;dr:
if the file is modified; then
mv /etc/pki/tls/openssl.cnf{,rpmsave_leapp}
mv /etc/pki/tls/openssl.cnf{.rpmnew,}
fi
"""

name = 'migrate_openssl_conf'
consumes = ()
produces = ()
tags = (IPUWorkflowTag, ApplicationsPhaseTag)

def process(self):
migrateopensslconf.process()
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import os

from leapp.libraries.stdlib import api, CalledProcessError, run

DEFAULT_OPENSSL_CONF = '/etc/pki/tls/openssl.cnf'
OPENSSL_CONF_RPMNEW = '{}.rpmnew'.format(DEFAULT_OPENSSL_CONF)
OPENSSL_CONF_BACKUP = '{}.leappsave'.format(DEFAULT_OPENSSL_CONF)


def _is_openssl_modified():
"""
Return True if modified in any way
"""
# NOTE(pstodulk): this is different from the approach in scansourcefiles,
# where we are interested about modified content. In this case, if the
# file is modified in any way, let's do something about that..
try:
run(['rpm', '-Vf', DEFAULT_OPENSSL_CONF])
except CalledProcessError:
return True
return False


def _safe_mv_file(src, dst):
"""
Move the file from src to dst. Return True on success, otherwise False.
"""
try:
run(['mv', src, dst])
except CalledProcessError:
return False
return True


def process():
if not _is_openssl_modified():
return
if not os.path.exists(OPENSSL_CONF_RPMNEW):
api.current_logger().debug('The {} file is modified, but *.rpmsave not found. Cannot do anything.')
return
if not _safe_mv_file(DEFAULT_OPENSSL_CONF, OPENSSL_CONF_BACKUP):
# NOTE(pstodulk): One of reasons could be the file is missing, however
# that's not expected to happen at all. If the file is missing before
# the upgrade, it will be installed by new openssl* package
api.current_logger().error(
'Could not back up the {} file. Skipping other actions.'
.format(DEFAULT_OPENSSL_CONF)
)
return
if not _safe_mv_file(OPENSSL_CONF_RPMNEW, DEFAULT_OPENSSL_CONF):
# unexpected, it's double seatbelt
api.current_logger().error('Cannot apply the new openssl configuration file! Restore it from the backup.')
if not _safe_mv_file(OPENSSL_CONF_BACKUP, DEFAULT_OPENSSL_CONF):
api.current_logger().error('Cannot restore the openssl configuration file!')
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
# '8' (etc..) -> files supposed to be scanned when particular major version of OS is used
TRACKED_FILES = {
'common': [
'/etc/pki/tls/openssl.cnf',
],
'8': [
],
Expand Down

0 comments on commit ae3a2b3

Please sign in to comment.