Blame SOURCES/0001-Fix-pki-healthcheck-for-clones.patch

914827
From 7d62105c676fc79e0c32766c41cd034655a524ff Mon Sep 17 00:00:00 2001
914827
From: "Endi S. Dewata" <edewata@redhat.com>
914827
Date: Tue, 25 Jan 2022 16:29:53 -0600
914827
Subject: [PATCH] Fix pki-healthcheck for clones
914827
914827
Previously the ClonesConnectivyAndDataCheck.check_kra_clones()
914827
was trying to check KRA clone status by retrieving a key using
914827
the subsystem cert. This operation did not work since the user
914827
associated with the cert did not have access to the keys. The
914827
code has been changed to get the status from GetStatus service
914827
instead. The original code might be moved into IPA later so it
914827
could run with IPA's RA agent credentials which would allow
914827
access to the keys.
914827
914827
Previously the ClonesPlugin.contact_subsystem_using_sslget()
914827
used sslget to call GetStatus service and returned the entire
914827
output which was then incorrectly processed in XML format. The
914827
method has been renamed to get_status() and changed to use
914827
PKIConnection and process the response in either JSON or XML
914827
format, then only return the subsystem status. All callers
914827
have been updated accordingly.
914827
914827
The ClonesPlugin.contact_subsystem_using_pki() is no longer
914827
used so it has been removed.
914827
---
914827
 .../clones/connectivity_and_data.py           | 130 ++++++++----------
914827
 .../pki/server/healthcheck/clones/plugin.py   |  75 ++++------
914827
 base/server/python/pki/server/__init__.py     |   8 +-
914827
 3 files changed, 91 insertions(+), 122 deletions(-)
914827
914827
diff --git a/base/server/healthcheck/pki/server/healthcheck/clones/connectivity_and_data.py b/base/server/healthcheck/pki/server/healthcheck/clones/connectivity_and_data.py
914827
index ca5d6dae48..d9bb480f7f 100644
914827
--- a/base/server/healthcheck/pki/server/healthcheck/clones/connectivity_and_data.py
914827
+++ b/base/server/healthcheck/pki/server/healthcheck/clones/connectivity_and_data.py
914827
@@ -46,93 +46,83 @@ class ClonesConnectivyAndDataCheck(ClonesPlugin):
914827
 
914827
     def check_kra_clones(self):
914827
         for host in self.clone_kras:
914827
-            cur_clone_msg = ' Host: ' + host.Hostname + ' Port: ' + host.SecurePort
914827
-            # Reach out and get some keys or requests , to serve as a data and connectivity check
914827
+
914827
+            url = 'https://' + host.Hostname + ':' + host.SecurePort
914827
+
914827
             try:
914827
-                client_nick = self.security_domain.config.get('ca.connector.KRA.nickName')
914827
-
914827
-                output = self.contact_subsystem_using_pki(
914827
-                    host.SecurePort, host.Hostname, client_nick,
914827
-                    self.passwd, self.db_dir, 'kra-key-show', ['0x01'])
914827
-
914827
-                # check to see if we either got a key or a key not found exception
914827
-                # of which either will imply a successful connection
914827
-                if output is not None:
914827
-                    key_found = output.find('Key ID:')
914827
-                    key_not_found = output.find('KeyNotFoundException:')
914827
-                    if key_found >= 0:
914827
-                        logger.info('Key material found from kra clone.')
914827
-
914827
-                    if key_not_found >= 0:
914827
-                        logger.info('key not found, possibly empty kra')
914827
-
914827
-                    if key_not_found == -1 and key_found == -1:
914827
-                        logger.info('Failure to get key material from kra')
914827
-                        raise BaseException('KRA clone problem detected ' + cur_clone_msg)
914827
-                else:
914827
-                    raise BaseException('No data obtained from KRA clone.' + cur_clone_msg)
914827
+                status = self.get_status(
914827
+                    host.Hostname,
914827
+                    host.SecurePort,
914827
+                    '/kra/admin/kra/getStatus')
914827
 
914827
-            except BaseException as e:
914827
-                logger.error("Internal error testing KRA clone. %s", e)
914827
-                raise BaseException('Internal error testing KRA clone.' + cur_clone_msg)
914827
+                logger.info('KRA at %s is %s', url, status)
914827
 
914827
-        return
914827
+                if status != 'running':
914827
+                    raise Exception('KRA at %s is %s' % (url, status))
914827
+
914827
+            except Exception as e:
914827
+                logger.error('Unable to reach KRA at %s: %s', url, e)
914827
+                raise Exception('Unable to reach KRA at %s: %s' % (url, e))
914827
 
914827
     def check_ocsp_clones(self):
914827
         for host in self.clone_ocsps:
914827
-            cur_clone_msg = ' Host: ' + host.Hostname + ' Port: ' + host.SecurePort
914827
-            # Reach out to the ocsp clones
914827
+
914827
+            url = 'https://' + host.Hostname + ':' + host.SecurePort
914827
+
914827
             try:
914827
-                output = self.contact_subsystem_using_sslget(
914827
-                    host.SecurePort, host.Hostname, None,
914827
-                    self.passwd, self.db_dir, None, '/ocsp/admin/ocsp/getStatus')
914827
-
914827
-                good_status = output.find('<State>1</State>')
914827
-                if good_status == -1:
914827
-                    raise BaseException('OCSP clone problem detected.' + cur_clone_msg)
914827
-                logger.info('good_status %s ', good_status)
914827
-            except BaseException as e:
914827
-                logger.error("Internal error testing OCSP clone.  %s", e)
914827
-                raise BaseException('Internal error testing OCSP clone.' + cur_clone_msg)
914827
+                status = self.get_status(
914827
+                    host.Hostname,
914827
+                    host.SecurePort,
914827
+                    '/ocsp/admin/ocsp/getStatus')
914827
 
914827
-        return
914827
+                logger.info('OCSP at %s is %s', url, status)
914827
+
914827
+                if status != 'running':
914827
+                    raise Exception('OCSP at %s is %s' % (url, status))
914827
+
914827
+            except Exception as e:
914827
+                logger.error('Unable to reach OCSP at %s: %s', url, e)
914827
+                raise Exception('Unable to reach OCSP at %s: %s' % (url, e))
914827
 
914827
     def check_tks_clones(self):
914827
         for host in self.clone_tkss:
914827
-            cur_clone_msg = ' Host: ' + host.Hostname + ' Port: ' + host.SecurePort
914827
-            # Reach out to the tks clones
914827
+
914827
+            url = 'https://' + host.Hostname + ':' + host.SecurePort
914827
+
914827
             try:
914827
-                output = self.contact_subsystem_using_sslget(
914827
-                    host.SecurePort, host.Hostname, None,
914827
-                    self.passwd, self.db_dir, None, '/tks/admin/tks/getStatus')
914827
-
914827
-                good_status = output.find('<State>1</State>')
914827
-                if good_status == -1:
914827
-                    raise BaseException('TKS clone problem detected.' + cur_clone_msg)
914827
-                logger.info('good_status %s ', good_status)
914827
-            except BaseException as e:
914827
-                logger.error("Internal error testing TKS clone. %s", e)
914827
-                raise BaseException('Internal error testing TKS clone.' + cur_clone_msg)
914827
+                status = self.get_status(
914827
+                    host.Hostname,
914827
+                    host.SecurePort,
914827
+                    '/tks/admin/tks/getStatus')
914827
 
914827
-        return
914827
+                logger.info('TKS at %s is %s', url, status)
914827
+
914827
+                if status != 'running':
914827
+                    raise Exception('TKS at %s is %s' % (url, status))
914827
+
914827
+            except Exception as e:
914827
+                logger.error('Unable to reach TKS at %s: %s', url, e)
914827
+                raise Exception('Unable to reach TKS at %s: %s' % (url, e))
914827
 
914827
     def check_tps_clones(self):
914827
         for host in self.clone_tpss:
914827
-            cur_clone_msg = ' Host: ' + host.Hostname + ' Port: ' + host.SecurePort
914827
-            # Reach out to the tps clones
914827
+
914827
+            url = 'https://' + host.Hostname + ':' + host.SecurePort
914827
+
914827
             try:
914827
-                output = self.contact_subsystem_using_sslget(
914827
-                    host.SecurePort, host.Hostname, None,
914827
-                    self.passwd, self.db_dir, None, '/tps/admin/tps/getStatus')
914827
-
914827
-                good_status = output.find('<State>1</State>')
914827
-                if good_status == -1:
914827
-                    raise BaseException('TPS clone problem detected.' + cur_clone_msg)
914827
-                logger.info('good_status  %s ', good_status)
914827
-            except BaseException as e:
914827
-                logger.error("Internal error testing TPS clone. %s", e)
914827
-                raise BaseException('Internal error testing TPS clone.' + cur_clone_msg)
914827
-        return
914827
+                status = self.get_status(
914827
+                    host.Hostname,
914827
+                    host.SecurePort,
914827
+                    '/tps/admin/tps/getStatus')
914827
+
914827
+                logger.info('TPS at %s is %s', url, status)
914827
+
914827
+                if status != 'running':
914827
+                    raise Exception('TPS at %s is %s' % (url, status))
914827
+
914827
+            except Exception as e:
914827
+                logger.error('Unable to reach TPS at %s: %s', url, e)
914827
+                raise Exception('Unable to reach TPS at %s: %s' % (url, e))
914827
 
914827
     @duration
914827
     def check(self):
914827
diff --git a/base/server/healthcheck/pki/server/healthcheck/clones/plugin.py b/base/server/healthcheck/pki/server/healthcheck/clones/plugin.py
914827
index 2472f35b5b..824c36a1a9 100644
914827
--- a/base/server/healthcheck/pki/server/healthcheck/clones/plugin.py
914827
+++ b/base/server/healthcheck/pki/server/healthcheck/clones/plugin.py
914827
@@ -6,6 +6,10 @@
914827
 # SPDX-License-Identifier: GPL-2.0-or-later
914827
 #
914827
 
914827
+import json
914827
+import logging
914827
+import xml.etree.ElementTree as ET
914827
+
914827
 from ipahealthcheck.core.plugin import Plugin, Registry
914827
 from pki.server.instance import PKIInstance
914827
 from pki.client import PKIConnection
914827
@@ -13,9 +17,6 @@ from pki.system import SecurityDomainClient
914827
 
914827
 from pki.server.healthcheck.core.main import merge_dogtag_config
914827
 
914827
-import logging
914827
-import subprocess
914827
-
914827
 logger = logging.getLogger(__name__)
914827
 
914827
 # Temporary workaround to skip VERBOSE data. Fix already pushed to upstream
914827
@@ -46,60 +47,36 @@ class ClonesPlugin(Plugin):
914827
 
914827
         self.instance = PKIInstance(self.config.instance_name)
914827
 
914827
-    def contact_subsystem_using_pki(
914827
-            self, subport, subhost, subsystemnick,
914827
-            token_pwd, db_path, cmd, exts=None):
914827
-        command = ["/usr/bin/pki",
914827
-                   "-p", str(subport),
914827
-                   "-h", subhost,
914827
-                   "-n", subsystemnick,
914827
-                   "-P", "https",
914827
-                   "-d", db_path,
914827
-                   "-c", token_pwd,
914827
-                   cmd]
914827
-
914827
-        if exts is not None:
914827
-            command.extend(exts)
914827
-
914827
-        output = None
914827
-        try:
914827
-            output = subprocess.check_output(command, stderr=subprocess.STDOUT)
914827
-        except subprocess.CalledProcessError as e:
914827
-            output = e.output.decode('utf-8')
914827
-            return output
914827
+    def get_status(self, host, port, path):
914827
 
914827
-        output = output.decode('utf-8')
914827
+        self.instance.export_ca_cert()
914827
 
914827
-        return output
914827
+        connection = PKIConnection(
914827
+            protocol='https',
914827
+            hostname=host,
914827
+            port=port,
914827
+            cert_paths=self.instance.ca_cert)
914827
 
914827
-    def contact_subsystem_using_sslget(
914827
-            self, port, host, subsystemnick,
914827
-            token_pwd, db_path, params, url):
914827
+        response = connection.get(path)
914827
 
914827
-        command = ["/usr/bin/sslget"]
914827
+        content_type = response.headers['Content-Type']
914827
+        content = response.text
914827
+        logger.info('Content:\n%s', content)
914827
 
914827
-        if subsystemnick is not None:
914827
-            command.extend(["-n", subsystemnick])
914827
+        # https://github.com/dogtagpki/pki/wiki/GetStatus-Service
914827
+        if content_type == 'application/json':
914827
+            json_response = json.loads(content)
914827
+            status = json_response['Response']['Status']
914827
 
914827
-        command.extend(["-p", token_pwd, "-d", db_path])
914827
-
914827
-        if params is not None:
914827
-            command.extend(["-e", params])
914827
-
914827
-        command.extend([
914827
-            "-r", url, host + ":" + port])
914827
-
914827
-        logger.info(' command : %s ', command)
914827
-        output = None
914827
-        try:
914827
-            output = subprocess.check_output(command, stderr=subprocess.STDOUT)
914827
-        except subprocess.CalledProcessError as e:
914827
-            output = e.output.decode('utf-8')
914827
-            return output
914827
+        elif content_type == 'application/xml':
914827
+            root = ET.fromstring(content)
914827
+            status = root.findtext('Status')
914827
 
914827
-        output = output.decode('utf-8')
914827
+        else:
914827
+            raise Exception('Unsupported content-type: %s' % content_type)
914827
 
914827
-        return output
914827
+        logger.info('Status: %s', status)
914827
+        return status
914827
 
914827
     def get_security_domain_data(self, host, port):
914827
         domain_data = None
914827
diff --git a/base/server/python/pki/server/__init__.py b/base/server/python/pki/server/__init__.py
914827
index 4fbb74684b..0515bbb197 100644
914827
--- a/base/server/python/pki/server/__init__.py
914827
+++ b/base/server/python/pki/server/__init__.py
914827
@@ -241,6 +241,10 @@ class PKIServer(object):
914827
     def jss_conf(self):
914827
         return os.path.join(self.conf_dir, 'jss.conf')
914827
 
914827
+    @property
914827
+    def ca_cert(self):
914827
+        return os.path.join(self.nssdb_dir, 'ca.crt')
914827
+
914827
     def is_valid(self):
914827
         return self.exists()
914827
 
914827
@@ -259,8 +263,6 @@ class PKIServer(object):
914827
 
914827
     def export_ca_cert(self):
914827
 
914827
-        ca_path = os.path.join(self.nssdb_dir, 'ca.crt')
914827
-
914827
         token = pki.nssdb.INTERNAL_TOKEN_NAME
914827
         nickname = self.get_sslserver_cert_nickname()
914827
 
914827
@@ -272,7 +274,7 @@ class PKIServer(object):
914827
         nssdb = self.open_nssdb(token=token)
914827
 
914827
         try:
914827
-            nssdb.extract_ca_cert(ca_path, nickname)
914827
+            nssdb.extract_ca_cert(self.ca_cert, nickname)
914827
         finally:
914827
             nssdb.close()
914827
 
914827
-- 
914827
2.33.1
914827