Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

setup: Allow renewing certificates during the warning period #486

Merged
merged 1 commit into from
Jun 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 35 additions & 5 deletions packaging/setup/ovirt_engine_setup/engine_common/pki_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
from cryptography.x509.extensions import ExtensionNotFound

from ovirt_engine_setup.engine import constants as oenginecons
from ovirt_engine_setup.engine import vdcoption
from ovirt_engine_setup.engine_common import database


def x509_load_cert(fname):
Expand All @@ -33,8 +35,13 @@ def x509_load_cert(fname):
)


def cert_expires(x509cert):
# input: x509cert: cryptography.x509.Certificate object
def cert_expires(x509cert, short_life, environment, logger):
# input:
# - logger: The logger to use for logging
# - x509cert: cryptography.x509.Certificate object
# - short_life: Whether the certificate is a short-life (e.g. browser)
# certificate.
# - environment: Environment to pass to database.Statement
# return: bool

#
Expand All @@ -59,10 +66,28 @@ def cert_expires(x509cert):
# py cryptography to support timezones or by using other
# means, such as calling the openssl utility, e.g.
# openssl x509 -in ca.pem -noout -startdate
if short_life:
days = 60
else:
try:
days_str = vdcoption.VdcOption(
statement=database.Statement(
dbenvkeys=oenginecons.Const.ENGINE_DB_ENV_KEYS,
environment=environment,
),
).getVdcOption(
'CertExpirationWarnPeriodInDays',
ownConnection=True,
)
days = int(days_str)
except Exception as e:
logger.info("CertExpirationWarnPeriodInDays config value not "
"available, using 365 days: %s", e)
days = 365
return (
x509cert.not_valid_after.replace(tzinfo=None) -
datetime.datetime.utcnow() <
datetime.timedelta(days=60)
datetime.timedelta(days=days)
)


Expand All @@ -88,16 +113,21 @@ def cert_has_SAN(logger, x509cert):
return res


def ok_to_renew_cert(logger, x509cert, ca_cert, name, extract):
def ok_to_renew_cert(logger, x509cert, ca_cert, name, extract, short_life,
environment):
# input:
# - logger: The logger to use for logging
# - x509cert: cryptography.x509.Certificate object
# - ca_cert: cryptography.x509.Certificate object
# - name: A base name (--name param of pki-* scripts)
# - extract: bool. If True, we need to check the extracted cert
# - short_life: Whether the certificate is a short-life (e.g. browser)
# certificate.
# - environment: Environment to pass to database.Statement
# return: bool
res = False
if x509cert and (
cert_expires(x509cert) or
cert_expires(x509cert, short_life, environment, logger) or
not cert_has_SAN(logger, x509cert)
):
if not extract or ca_cert is None:
Expand Down
2 changes: 2 additions & 0 deletions packaging/setup/ovirt_engine_setup/remote_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,8 @@ def enroll_cert(self):
None,
self._base_name,
True,
False,
self.environment,
):
self._need_cert = True

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ def _enrollCertificate(self, name, uninstall_files, keepKey=False,
},
)

def _ok_to_renew_cert(self, pkcs12, name, extract):
def _ok_to_renew_cert(self, pkcs12, name, extract, short_life):
# input:
# - pkcs12: A PKCS#12 file name
# - name: A base name (--name param of pki-* scripts)
Expand All @@ -312,6 +312,8 @@ def _ok_to_renew_cert(self, pkcs12, name, extract):
),
name,
extract,
short_life,
self.environment,
)

def _enrollCertificates(self, renew, uninstall_files):
Expand Down Expand Up @@ -339,7 +341,8 @@ def _enrollCertificates(self, renew, uninstall_files):
enroll = self._ok_to_renew_cert(
pkcs12,
entry['name'],
entry['extract']
entry['extract'],
entry['shortLife'],
)

if enroll:
Expand Down Expand Up @@ -496,7 +499,8 @@ def _customization(self):
)
def _customization_upgrade(self):
if True in [
pki_utils.cert_expires(pki_utils.x509_load_cert(cert))
pki_utils.cert_expires(pki_utils.x509_load_cert(cert), False,
self.environment, self.logger)
for cert in self._CA_FILES
if os.path.exists(cert)
] + [
Expand All @@ -506,7 +510,8 @@ def _customization_upgrade(self):
'%s.p12' % entry['name']
),
entry['name'],
entry['extract']
entry['extract'],
entry['shortLife'],
)
for entry in self.environment[oenginecons.PKIEnv.ENTITIES]
]:
Expand Down Expand Up @@ -718,7 +723,12 @@ def _template_aia(template):
for ca_file in self._CA_FILES:
if (
os.path.exists(ca_file) and
pki_utils.cert_expires(pki_utils.x509_load_cert(ca_file))
pki_utils.cert_expires(
pki_utils.x509_load_cert(ca_file),
False,
self.environment,
self.logger,
)
):
self._renewed_ca_files.add(ca_file)
self.logger.info(_('Renewing CA: %s'), ca_file)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,25 @@ def _(m):
return gettext.dgettext(message=m, domain='ovirt-engine-setup')


def _refresh_needed(cert_path, check_cert=True):
ca_cert_path = oenginecons.FileLocations.OVIRT_ENGINE_PKI_ENGINE_CA_CERT
return (not os.path.exists(cert_path) or
os.stat(ca_cert_path).st_mtime > os.stat(cert_path).st_mtime or
(check_cert and
pki_utils.cert_expires(pki_utils.x509_load_cert(cert_path))))


@util.export
class Plugin(plugin.PluginBase):
"""vmconsole proxy configuration plugin."""

def _subjectComponentEscape(self, s):
return outil.escape(s, '/\\')

def _refresh_needed(self, cert_path, check_cert=True):
ca_path = oenginecons.FileLocations.OVIRT_ENGINE_PKI_ENGINE_CA_CERT
return (not os.path.exists(cert_path) or
os.stat(ca_path).st_mtime > os.stat(cert_path).st_mtime or
(check_cert and
pki_utils.cert_expires(
pki_utils.x509_load_cert(cert_path),
False,
self.environment,
self.logger,
)))

def _enrollSSHKeys(self, host_mode, uninstall_files):
suffix = 'host' if host_mode else 'user'
name = '%s-%s' % (
Expand Down Expand Up @@ -187,7 +191,7 @@ def _setup(self):
condition=lambda self: (
self.environment[
ovmpcons.ConfigEnv.VMCONSOLE_PROXY_CONFIG
] and _refresh_needed(
] and self._refresh_needed(
ovmpcons.FileLocations.
OVIRT_ENGINE_PKI_VMCONSOLE_PROXY_HELPER_CERT
)
Expand Down Expand Up @@ -293,15 +297,15 @@ def _ssh_cert_file(self, suffix):
self.environment[
ovmpcons.ConfigEnv.VMCONSOLE_PROXY_CONFIG
] and (
_refresh_needed(
self._refresh_needed(
os.path.join(
ovmpcons.FileLocations.VMCONSOLE_PKI_DIR,
'proxy-ssh_host_rsa',
),
check_cert=False
) or
_refresh_needed(self._ssh_cert_file('user')) or
_refresh_needed(self._ssh_cert_file('host'))
self._refresh_needed(self._ssh_cert_file('user')) or
self._refresh_needed(self._ssh_cert_file('host'))
)
),
)
Expand Down