Blame SOURCES/0005-Add-check-for-IPA-KRA-Agent.patch

cf0866
From 3f6ed4393dfa9ddf982e326065a3ea160bef90b6 Mon Sep 17 00:00:00 2001
cf0866
From: Antonio Torres <antorres@redhat.com>
cf0866
Date: Tue, 23 Feb 2021 16:11:59 +0100
cf0866
Subject: [PATCH] Add check for IPA KRA Agent
cf0866
cf0866
Add check to validate KRA Agent in case KRA is installed, including
cf0866
checking for the KRA Agent LDAP entry.
cf0866
cf0866
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1894781
cf0866
Signed-off-by: Antonio Torres <antorres@redhat.com>
cf0866
---
cf0866
 README.md                       |  16 ++-
cf0866
 src/ipahealthcheck/ipa/certs.py | 167 +++++++++++++++++++-------------
cf0866
 2 files changed, 112 insertions(+), 71 deletions(-)
cf0866
cf0866
diff --git a/README.md b/README.md
cf0866
index b9c60a2..0f3ed6a 100644
cf0866
--- a/README.md
cf0866
+++ b/README.md
cf0866
@@ -547,7 +547,21 @@ Verify the description and userCertificate values in uid=ipara,ou=People,o=ipaca
cf0866
       "kw": {
cf0866
         "expected": "2;125;CN=Certificate Authority,O=EXAMPLE.TEST;CN=IPA RA,O=EXAMPLE.TEST",
cf0866
         "got": "2;7;CN=Certificate Authority,O=EXAMPLE.TEST;CN=IPA RA,O=EXAMPLE.TEST",
cf0866
-        "msg": "RA agent description does not match 2;7;CN=Certificate Authority,O=EXAMPLE.TEST;CN=IPA RA,O=EXAMPLE.TEST in LDAP and expected 2;125;CN=Certificate Authority,O=EXAMPLE.TEST;CN=IPA RA,O=EXAMPLE.TEST"
cf0866
+        "msg": "RA agent description does not match. Found 2;7;CN=Certificate Authority,O=EXAMPLE.TEST;CN=IPA RA,O=EXAMPLE.TEST in LDAP and expected 2;125;CN=Certificate Authority,O=EXAMPLE.TEST;CN=IPA RA,O=EXAMPLE.TEST"
cf0866
+      }
cf0866
+    }
cf0866
+
cf0866
+### IPAKRAAgent
cf0866
+Verify the description and userCertificate values in uid=ipakra,ou=people,o=kra,o=ipaca.
cf0866
+
cf0866
+    {
cf0866
+      "source": "ipahealthcheck.ipa.certs",
cf0866
+      "check": "IPAKRAAgent",
cf0866
+      "result": "ERROR",
cf0866
+      "kw": {
cf0866
+        "expected": "2;125;CN=Certificate Authority,O=EXAMPLE.TEST;CN=IPA RA,O=EXAMPLE.TEST",
cf0866
+        "got": "2;7;CN=Certificate Authority,O=EXAMPLE.TEST;CN=IPA RA,O=EXAMPLE.TEST",
cf0866
+        "msg": "KRA agent description does not match. Found 2;7;CN=Certificate Authority,O=EXAMPLE.TEST;CN=IPA RA,O=EXAMPLE.TEST in LDAP and expected 2;125;CN=Certificate Authority,O=EXAMPLE.TEST;CN=IPA RA,O=EXAMPLE.TEST"
cf0866
       }
cf0866
     }
cf0866
 
cf0866
diff --git a/src/ipahealthcheck/ipa/certs.py b/src/ipahealthcheck/ipa/certs.py
cf0866
index d3043d0..32c0d76 100644
cf0866
--- a/src/ipahealthcheck/ipa/certs.py
cf0866
+++ b/src/ipahealthcheck/ipa/certs.py
cf0866
@@ -724,6 +724,83 @@ class IPAOpenSSLChainValidation(IPAPlugin):
cf0866
                         self, constants.SUCCESS, key=cert)
cf0866
 
cf0866
 
cf0866
+def check_agent(plugin, base_dn, agent_type):
cf0866
+    """Check RA/KRA Agent"""
cf0866
+
cf0866
+    try:
cf0866
+        cert = x509.load_certificate_from_file(paths.RA_AGENT_PEM)
cf0866
+    except Exception as e:
cf0866
+        yield Result(plugin, constants.ERROR,
cf0866
+                     error=str(e),
cf0866
+                     msg='Unable to load RA cert: {error}')
cf0866
+        return
cf0866
+    serial_number = cert.serial_number
cf0866
+    subject = DN(cert.subject)
cf0866
+    issuer = DN(cert.issuer)
cf0866
+    description = '2;%d;%s;%s' % (serial_number, issuer, subject)
cf0866
+    logger.debug('%s agent description should be %s', agent_type, description)
cf0866
+    db_filter = ldap2.ldap2.combine_filters(
cf0866
+        [
cf0866
+            ldap2.ldap2.make_filter({'objectClass': 'inetOrgPerson'}),
cf0866
+            ldap2.ldap2.make_filter(
cf0866
+                {'description': ';%s;%s' % (issuer, subject)},
cf0866
+                exact=False, trailing_wildcard=False),
cf0866
+        ],
cf0866
+        ldap2.ldap2.MATCH_ALL)
cf0866
+    try:
cf0866
+        entries = plugin.conn.get_entries(base_dn,
cf0866
+                                          plugin.conn.SCOPE_SUBTREE,
cf0866
+                                          db_filter)
cf0866
+    except errors.NotFound:
cf0866
+        yield Result(plugin, constants.ERROR,
cf0866
+                     description=description,
cf0866
+                     msg='%s agent not found in LDAP' % agent_type)
cf0866
+        return
cf0866
+    except Exception as e:
cf0866
+        yield Result(plugin, constants.ERROR,
cf0866
+                     error=str(e),
cf0866
+                     msg='Retrieving %s agent from LDAP failed {error}'
cf0866
+                         % agent_type)
cf0866
+        return
cf0866
+    else:
cf0866
+        logger.debug('%s agent description is %s', agent_type, description)
cf0866
+        if len(entries) != 1:
cf0866
+            yield Result(plugin, constants.ERROR,
cf0866
+                         found=len(entries),
cf0866
+                         msg='Too many %s agent entries found, {found}'
cf0866
+                             % agent_type)
cf0866
+            return
cf0866
+        entry = entries[0]
cf0866
+        raw_desc = entry.get('description')
cf0866
+        if raw_desc is None:
cf0866
+            yield Result(plugin, constants.ERROR,
cf0866
+                         msg='%s agent is missing the description '
cf0866
+                             'attribute or it is not readable' % agent_type)
cf0866
+            return
cf0866
+        ra_desc = raw_desc[0]
cf0866
+        ra_certs = entry.get('usercertificate')
cf0866
+        if ra_desc != description:
cf0866
+            yield Result(plugin, constants.ERROR,
cf0866
+                         expected=description,
cf0866
+                         got=ra_desc,
cf0866
+                         msg='%s agent description does not match. Found '
cf0866
+                         '{got} in LDAP and expected {expected}' % agent_type)
cf0866
+            return
cf0866
+        found = False
cf0866
+        for candidate in ra_certs:
cf0866
+            if candidate == cert:
cf0866
+                found = True
cf0866
+                break
cf0866
+        if not found:
cf0866
+            yield Result(plugin, constants.ERROR,
cf0866
+                         certfile=paths.RA_AGENT_PEM,
cf0866
+                         dn=str(entry.dn),
cf0866
+                         msg='%s agent certificate in {certfile} not '
cf0866
+                             'found in LDAP userCertificate attribute '
cf0866
+                             'for the entry {dn}' % agent_type)
cf0866
+        yield Result(plugin, constants.SUCCESS)
cf0866
+
cf0866
+
cf0866
 @registry
cf0866
 class IPARAAgent(IPAPlugin):
cf0866
     """Validate the RA Agent used to talk to the CA
cf0866
@@ -739,82 +816,32 @@ class IPARAAgent(IPAPlugin):
cf0866
             logger.debug('CA is not configured, skipping RA Agent check')
cf0866
             return
cf0866
 
cf0866
-        try:
cf0866
-            cert = x509.load_certificate_from_file(paths.RA_AGENT_PEM)
cf0866
-        except Exception as e:
cf0866
-            yield Result(self, constants.ERROR,
cf0866
-                         error=str(e),
cf0866
-                         msg='Unable to load RA cert: {error}')
cf0866
-            return
cf0866
+        base_dn = DN('uid=ipara,ou=people,o=ipaca')
cf0866
+        yield from check_agent(self, base_dn, 'RA')
cf0866
 
cf0866
-        serial_number = cert.serial_number
cf0866
-        subject = DN(cert.subject)
cf0866
-        issuer = DN(cert.issuer)
cf0866
-        description = '2;%d;%s;%s' % (serial_number, issuer, subject)
cf0866
 
cf0866
-        logger.debug('RA agent description should be %s', description)
cf0866
+@registry
cf0866
+class IPAKRAAgent(IPAPlugin):
cf0866
+    """Validate the KRA Agent
cf0866
 
cf0866
-        db_filter = ldap2.ldap2.combine_filters(
cf0866
-            [
cf0866
-                ldap2.ldap2.make_filter({'objectClass': 'inetOrgPerson'}),
cf0866
-                ldap2.ldap2.make_filter({'sn': 'ipara'}),
cf0866
-                ldap2.ldap2.make_filter(
cf0866
-                    {'description': ';%s;%s' % (issuer, subject)},
cf0866
-                    exact=False, trailing_wildcard=False),
cf0866
-            ],
cf0866
-            ldap2.ldap2.MATCH_ALL)
cf0866
+       Compare the description and usercertificate values.
cf0866
+    """
cf0866
 
cf0866
-        base_dn = DN(('o', 'ipaca'))
cf0866
-        try:
cf0866
-            entries = self.conn.get_entries(base_dn,
cf0866
-                                            self.conn.SCOPE_SUBTREE,
cf0866
-                                            db_filter)
cf0866
-        except errors.NotFound:
cf0866
-            yield Result(self, constants.ERROR,
cf0866
-                         description=description,
cf0866
-                         msg='RA agent not found in LDAP')
cf0866
+    requires = ('dirsrv',)
cf0866
+
cf0866
+    @duration
cf0866
+    def check(self):
cf0866
+        if not self.ca.is_configured():
cf0866
+            logger.debug('CA is not configured, skipping KRA Agent check')
cf0866
             return
cf0866
-        except Exception as e:
cf0866
-            yield Result(self, constants.ERROR,
cf0866
-                         error=str(e),
cf0866
-                         msg='Retrieving RA agent from LDAP failed {error}')
cf0866
+
cf0866
+        kra = krainstance.KRAInstance(api.env.realm)
cf0866
+        if not kra.is_installed():
cf0866
+            logger.debug('KRA is not installed, skipping KRA Agent check')
cf0866
             return
cf0866
-        else:
cf0866
-            logger.debug('RA agent description is %s', description)
cf0866
-            if len(entries) != 1:
cf0866
-                yield Result(self, constants.ERROR,
cf0866
-                             found=len(entries),
cf0866
-                             msg='Too many RA agent entries found, {found}')
cf0866
-                return
cf0866
-            entry = entries[0]
cf0866
-            raw_desc = entry.get('description')
cf0866
-            if raw_desc is None:
cf0866
-                yield Result(self, constants.ERROR,
cf0866
-                             msg='RA agent is missing the description '
cf0866
-                                 'attribute or it is not readable')
cf0866
-                return
cf0866
-            ra_desc = raw_desc[0]
cf0866
-            ra_certs = entry.get('usercertificate')
cf0866
-            if ra_desc != description:
cf0866
-                yield Result(self, constants.ERROR,
cf0866
-                             expected=description,
cf0866
-                             got=ra_desc,
cf0866
-                             msg='RA agent description does not match. Found '
cf0866
-                             '{got} in LDAP and expected {expected}')
cf0866
-                return
cf0866
-            found = False
cf0866
-            for candidate in ra_certs:
cf0866
-                if candidate == cert:
cf0866
-                    found = True
cf0866
-                    break
cf0866
-            if not found:
cf0866
-                yield Result(self, constants.ERROR,
cf0866
-                             certfile=paths.RA_AGENT_PEM,
cf0866
-                             dn=str(entry.dn),
cf0866
-                             msg='RA agent certificate in {certfile} not '
cf0866
-                                 'found in LDAP userCertificate attribute '
cf0866
-                                 'for the entry {dn}')
cf0866
-            yield Result(self, constants.SUCCESS)
cf0866
+
cf0866
+        base_dn = DN('uid=ipakra,ou=people,o=kra,o=ipaca')
cf0866
+        yield from check_agent(self, base_dn, 'KRA')
cf0866
 
cf0866
 
cf0866
 @registry
cf0866
-- 
cf0866
2.26.2
cf0866