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

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