Skip to content

Commit

Permalink
If there are KRAs, ensure the renewal server is one
Browse files Browse the repository at this point in the history
If there are KRAs in the topology and there isn't one on
the renewal server then the KRA certificates will not be
renewed because they expect another server to do it for them.

Fixes: #125

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
  • Loading branch information
rcritten committed Apr 7, 2023
1 parent fa6b7ca commit 4185976
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 2 deletions.
47 changes: 47 additions & 0 deletions src/ipahealthcheck/ipa/roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from ipahealthcheck.core import constants

from ipalib import api
from ipaserver.install import krainstance

logger = logging.getLogger()

Expand Down Expand Up @@ -64,3 +65,49 @@ def check(self):
yield Result(self, constants.SUCCESS,
key='renewal_master',
master=server == api.env.host)


@registry
class IPARenewalMasterHasKRACheck(IPAPlugin):
"""
Determine if this master is the CA renewal master and has a KRA installed.
If this is the CA renewal master and there is a KRA in the topology
but not here then the KRA certificates will not be renewed.
"""
requires = ('dirsrv',)

@duration
def check(self):
try:
result = api.Command.config_show()
except Exception as e:
yield Result(self, constants.ERROR,
key='kra_renewal_master',
msg='Request for configuration failed, %s' % e)
return

renewal = result['result'].get('ca_renewal_master_server', None)
if renewal != api.env.host:
# Not the renewal server, nothing to do
logger.debug("Not the renewal server")
return

kra = krainstance.KRAInstance(api.env.realm)
if kra.is_installed():
yield Result(self, constants.SUCCESS,
key='kra_renewal_master')
return

if result['result'].get('kra_server_server'):
yield Result(self, constants.CRITICAL,
key='kra_renewal_master',
msg="There are KRA(s) in the topology but "
"not on the renewal server. "
"The KRA service certificates will not be "
"renewed.")
return

# it should never hit here but what the heck.
yield Result(self, constants.SUCCESS,
key='kra_renewal_master')
104 changes: 102 additions & 2 deletions tests/test_ipa_roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@

from base import BaseTest
from unittest.mock import patch
from util import capture_results, CAInstance
from util import capture_results, CAInstance, KRAInstance
from util import m_api

from ipahealthcheck.core import config, constants
from ipahealthcheck.ipa.plugin import registry
from ipahealthcheck.ipa.roles import (IPACRLManagerCheck,
IPARenewalMasterCheck)
IPARenewalMasterCheck,
IPARenewalMasterHasKRACheck)


class TestCRLManagerRole(BaseTest):
Expand Down Expand Up @@ -62,6 +63,7 @@ def test_crlmanager_no_ca(self, mock_ca):


class TestRenewalMaster(BaseTest):

def test_renewal_master_not_set(self):
framework = object()
registry.initialize(framework, config.Config)
Expand Down Expand Up @@ -123,3 +125,101 @@ def test_is_renewal_master(self):
assert result.source == 'ipahealthcheck.ipa.roles'
assert result.check == 'IPARenewalMasterCheck'
assert result.kw.get('master') is True

@patch('ipaserver.install.krainstance.KRAInstance')
def test_is_renewal_master_with_kra(self, mock_kra):
"""Server is the renewal master and has a KRA configured"""
framework = object()
mock_kra.return_value = KRAInstance(True)

registry.initialize(framework, config.Config)

m_api.Command.config_show.side_effect = [{
'result': {
'ca_renewal_master_server': 'server.ipa.example',
'kra_server_server': 'server.ipa.example'
}
}]

f = IPARenewalMasterHasKRACheck(registry)

self.results = capture_results(f)

assert len(self.results) == 1

result = self.results.results[0]
assert result.result == constants.SUCCESS
assert result.source == 'ipahealthcheck.ipa.roles'
assert result.check == 'IPARenewalMasterHasKRACheck'

@patch('ipaserver.install.krainstance.KRAInstance')
def test_is_renewal_master_with_no_kra(self, mock_kra):
"""Server is the renewal master and does not have KRA configured"""
framework = object()
mock_kra.return_value = KRAInstance(False)

registry.initialize(framework, config.Config)

m_api.Command.config_show.side_effect = [{
'result': {
'ca_renewal_master_server': 'server.ipa.example',
'kra_server_server': 'replica.ipa.example'
}
}]

f = IPARenewalMasterHasKRACheck(registry)

self.results = capture_results(f)

assert len(self.results) == 1

result = self.results.results[0]
assert result.result == constants.CRITICAL
assert result.source == 'ipahealthcheck.ipa.roles'
assert result.check == 'IPARenewalMasterHasKRACheck'

@patch('ipaserver.install.krainstance.KRAInstance')
def test_is_renewal_master_with_no_kras(self, mock_kra):
"""Server is the renewal master no KRAs are configured"""
framework = object()
mock_kra.return_value = KRAInstance(False)

registry.initialize(framework, config.Config)

m_api.Command.config_show.side_effect = [{
'result': {
'ca_renewal_master_server': 'server.ipa.example'
}
}]

f = IPARenewalMasterHasKRACheck(registry)

self.results = capture_results(f)

assert len(self.results) == 1

result = self.results.results[0]
assert result.result == constants.SUCCESS
assert result.source == 'ipahealthcheck.ipa.roles'
assert result.check == 'IPARenewalMasterHasKRACheck'

@patch('ipaserver.install.krainstance.KRAInstance')
def test_not_renewal_master_kra_check(self, mock_kra):
"""Server is not the renewal master no KRA check needed"""
framework = object()
mock_kra.return_value = KRAInstance(False)

registry.initialize(framework, config.Config)

m_api.Command.config_show.side_effect = [{
'result': {
'ca_renewal_master_server': 'replica.ipa.example'
}
}]

f = IPARenewalMasterHasKRACheck(registry)

self.results = capture_results(f)

# No result is returned if not the renewal server
assert len(self.results) == 0

0 comments on commit 4185976

Please sign in to comment.