diff --git a/.github/workflows/ca-existing-ds-test.yml b/.github/workflows/ca-existing-ds-test.yml index dbafece7976..8179cf5637b 100644 --- a/.github/workflows/ca-existing-ds-test.yml +++ b/.github/workflows/ca-existing-ds-test.yml @@ -124,6 +124,10 @@ jobs: --cert admin.crt \ caadmin + - name: Create CA subsystem + run: | + docker exec pki pki-server ca-create -v + - name: Set up DS container run: | tests/bin/ds-container-create.sh ds @@ -135,6 +139,34 @@ jobs: - name: Connect DS container to network run: docker network connect example ds --alias ds.example.com + - name: Configure connection to CA database + run: | + # store DS password + docker exec pki pki-server password-add \ + --password Secret.123 \ + internaldb + + # configure DS connection params + docker exec pki pki-server ca-db-config-mod \ + --hostname ds.example.com \ + --port 3389 \ + --secure false \ + --auth BasicAuth \ + --bindDN "cn=Directory Manager" \ + --bindPWPrompt internaldb \ + --database userroot \ + --baseDN dc=ca,dc=pki,dc=example,dc=com \ + --multiSuffix false \ + --maxConns 15 \ + --minConns 3 + + # configure user/group subsystem to use DS + docker exec pki pki-server ca-config-set usrgrp.ldap internaldb + + - name: Check connection to CA database + run: | + docker exec pki pki-server ca-db-info + # https://github.com/dogtagpki/pki/wiki/Setting-up-CA-Database - name: Configure DS database run: | @@ -238,257 +270,61 @@ jobs: - name: Add CA VLV indexes run: | - sed \ - -e 's/{instanceId}/pki-tomcat/g' \ - -e 's/{database}/userroot/g' \ - -e 's/{rootSuffix}/dc=ca,dc=pki,dc=example,dc=com/g' \ - base/ca/database/ds/vlv.ldif \ - | tee vlv.ldif - docker exec ds ldapadd \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 \ - -f $SHARED/vlv.ldif + docker exec pki pki-server ca-db-vlv-add -v - name: Rebuild CA VLV indexes run: | - # start rebuild task - sed \ - -e 's/{database}/userroot/g' \ - -e 's/{instanceId}/pki-tomcat/g' \ - base/ca/database/ds/vlvtasks.ldif \ - | tee vlvtasks.ldif - docker exec ds ldapadd \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 \ - -f $SHARED/vlvtasks.ldif - - # wait for task to complete - while true; do - sleep 1 - - docker exec ds ldapsearch \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 \ - -b "cn=index1160589769, cn=index, cn=tasks, cn=config" \ - -LLL \ - nsTaskExitCode \ - | tee output - - sed -n -e 's/nsTaskExitCode:\s*\(.*\)/\1/p' output > nsTaskExitCode - cat nsTaskExitCode - - if [ -s nsTaskExitCode ]; then - break - fi - done - - echo "0" > expected - diff expected nsTaskExitCode + docker exec pki pki-server ca-db-vlv-reindex -v # https://github.com/dogtagpki/pki/wiki/Setting-up-CA-Database-User - name: Add database user run: | - docker exec -i ds ldapadd \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 << EOF - dn: uid=pkidbuser,ou=people,dc=ca,dc=pki,dc=example,dc=com - objectClass: person - objectClass: organizationalPerson - objectClass: inetOrgPerson - objectClass: cmsuser - cn: pkidbuser - sn: pkidbuser - uid: pkidbuser - userState: 1 - userType: agentType - nsPagedSizeLimit: 20000 - EOF + docker exec pki pki-server ca-user-add \ + --full-name pkidbuser \ + --type agentType \ + pkidbuser - name: Assign subsystem cert to database user run: | - # convert cert from PEM to DER - docker cp pki:/etc/pki/pki-tomcat/certs/subsystem.crt subsystem.crt - openssl x509 -outform der -in subsystem.crt -out subsystem.der - - # get serial number - docker exec pki pki \ - -d /etc/pki/pki-tomcat/alias \ - -f /etc/pki/pki-tomcat/password.conf \ - nss-cert-show \ - subsystem | tee output - sed -n 's/^ *Serial Number: *\(.*\)/\1/p' output > subsystem.serial - - HEX_SERIAL=$(cat subsystem.serial) - echo "HEX_SERIAL: $HEX_SERIAL" - - DEC_SERIAL=$(python -c "print(int('$HEX_SERIAL', 16))") - echo "DEC_SERIAL: $DEC_SERIAL" - - docker exec -i ds ldapmodify \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 << EOF - dn: uid=pkidbuser,ou=people,dc=ca,dc=pki,dc=example,dc=com - changetype: modify - add: description - description: 2;$DEC_SERIAL;CN=CA Signing Certificate;CN=Subsystem Certificate - - - add: seeAlso - seeAlso: CN=Subsystem Certificate - - - add: userCertificate - userCertificate:< file:$SHARED/subsystem.der - - - EOF + docker exec pki pki-server ca-user-cert-add \ + --cert /etc/pki/pki-tomcat/certs/subsystem.crt \ + pkidbuser - name: Add database user into CA groups run: | - docker exec -i ds ldapmodify \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 << EOF - dn: cn=Subsystem Group,ou=groups,dc=ca,dc=pki,dc=example,dc=com - changetype: modify - add: uniqueMember - uniqueMember: uid=pkidbuser,ou=people,dc=ca,dc=pki,dc=example,dc=com - - - - dn: cn=Certificate Manager Agents,ou=groups,dc=ca,dc=pki,dc=example,dc=com - changetype: modify - add: uniqueMember - uniqueMember: uid=pkidbuser,ou=people,dc=ca,dc=pki,dc=example,dc=com - - - EOF + docker exec pki pki-server ca-user-role-add pkidbuser "Subsystem Group" + docker exec pki pki-server ca-user-role-add pkidbuser "Certificate Manager Agents" - - name: Grant database user access to CA database + - name: Grant database access to database user run: | - sed \ - -e 's/{rootSuffix}/dc=example,dc=com/g' \ - -e 's/{dbuser}/uid=pkidbuser,ou=people,dc=ca,dc=pki,dc=example,dc=com/g' \ - base/server/database/ds/db-access-grant.ldif \ - | tee db-access-grant.ldif - docker exec ds ldapadd \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 \ - -f $SHARED/db-access-grant.ldif \ - -c + docker exec pki pki-server ca-db-access-grant \ + uid=pkidbuser,ou=people,dc=ca,dc=pki,dc=example,dc=com # https://github.com/dogtagpki/pki/wiki/Setting-up-CA-Admin-User - name: Add CA admin user run: | - docker exec -i ds ldapadd \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 << EOF - dn: uid=caadmin,ou=people,dc=ca,dc=pki,dc=example,dc=com - objectClass: person - objectClass: organizationalPerson - objectClass: inetOrgPerson - objectClass: cmsuser - cn: caadmin - sn: caadmin - uid: caadmin - mail: caadmin@example.com - userPassword: Secret.123 - userState: 1 - userType: adminType - EOF + docker exec pki pki-server ca-user-add \ + --full-name Administrator \ + --type adminType \ + caadmin - name: Assign CA admin cert to CA admin user run: | - # convert cert from PEM to DER - docker cp pki:admin.crt admin.crt - openssl x509 -outform der -in admin.crt -out admin.der - - # get serial number - docker exec pki pki nss-cert-show caadmin | tee output - sed -n 's/^ *Serial Number: *\(.*\)/\1/p' output > caadmin.serial - - HEX_SERIAL=$(cat caadmin.serial) - echo "HEX_SERIAL: $HEX_SERIAL" - - DEC_SERIAL=$(python -c "print(int('$HEX_SERIAL', 16))") - echo "DEC_SERIAL: $DEC_SERIAL" - - docker exec -i ds ldapmodify \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 << EOF - dn: uid=caadmin,ou=people,dc=ca,dc=pki,dc=example,dc=com - changetype: modify - add: description - description: 2;$DEC_SERIAL;CN=CA Signing Certificate;CN=Administrator - - - add: userCertificate - userCertificate:< file:$SHARED/admin.der - - - EOF + docker exec pki pki-server ca-user-cert-add \ + --cert admin.crt \ + caadmin - - name: Add CA admin user into CA groups + - name: Assign roles to CA admin user run: | - docker exec -i ds ldapmodify \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 << EOF - dn: cn=Administrators,ou=groups,dc=ca,dc=pki,dc=example,dc=com - changetype: modify - add: uniqueMember - uniqueMember: uid=caadmin,ou=people,dc=ca,dc=pki,dc=example,dc=com - - - - dn: cn=Certificate Manager Agents,ou=groups,dc=ca,dc=pki,dc=example,dc=com - changetype: modify - add: uniqueMember - uniqueMember: uid=caadmin,ou=people,dc=ca,dc=pki,dc=example,dc=com - - - - dn: cn=Security Domain Administrators,ou=groups,dc=ca,dc=pki,dc=example,dc=com - changetype: modify - add: uniqueMember - uniqueMember: uid=caadmin,ou=people,dc=ca,dc=pki,dc=example,dc=com - - - - dn: cn=Enterprise CA Administrators,ou=groups,dc=ca,dc=pki,dc=example,dc=com - changetype: modify - add: uniqueMember - uniqueMember: uid=caadmin,ou=people,dc=ca,dc=pki,dc=example,dc=com - - - - dn: cn=Enterprise KRA Administrators,ou=groups,dc=ca,dc=pki,dc=example,dc=com - changetype: modify - add: uniqueMember - uniqueMember: uid=caadmin,ou=people,dc=ca,dc=pki,dc=example,dc=com - - - - dn: cn=Enterprise RA Administrators,ou=groups,dc=ca,dc=pki,dc=example,dc=com - changetype: modify - add: uniqueMember - uniqueMember: uid=caadmin,ou=people,dc=ca,dc=pki,dc=example,dc=com - - - - dn: cn=Enterprise TKS Administrators,ou=groups,dc=ca,dc=pki,dc=example,dc=com - changetype: modify - add: uniqueMember - uniqueMember: uid=caadmin,ou=people,dc=ca,dc=pki,dc=example,dc=com - - - - dn: cn=Enterprise OCSP Administrators,ou=groups,dc=ca,dc=pki,dc=example,dc=com - changetype: modify - add: uniqueMember - uniqueMember: uid=caadmin,ou=people,dc=ca,dc=pki,dc=example,dc=com - - - - dn: cn=Enterprise TPS Administrators,ou=groups,dc=ca,dc=pki,dc=example,dc=com - changetype: modify - add: uniqueMember - uniqueMember: uid=caadmin,ou=people,dc=ca,dc=pki,dc=example,dc=com - - - EOF + docker exec pki pki-server ca-user-role-add caadmin "Administrators" + docker exec pki pki-server ca-user-role-add caadmin "Certificate Manager Agents" + docker exec pki pki-server ca-user-role-add caadmin "Security Domain Administrators" + docker exec pki pki-server ca-user-role-add caadmin "Enterprise CA Administrators" + docker exec pki pki-server ca-user-role-add caadmin "Enterprise KRA Administrators" + docker exec pki pki-server ca-user-role-add caadmin "Enterprise RA Administrators" + docker exec pki pki-server ca-user-role-add caadmin "Enterprise TKS Administrators" + docker exec pki pki-server ca-user-role-add caadmin "Enterprise OCSP Administrators" + docker exec pki pki-server ca-user-role-add caadmin "Enterprise TPS Administrators" - name: Install CA run: | diff --git a/base/server/python/pki/server/__init__.py b/base/server/python/pki/server/__init__.py index 4ebfd3252cf..17ed31c0db2 100644 --- a/base/server/python/pki/server/__init__.py +++ b/base/server/python/pki/server/__init__.py @@ -1199,10 +1199,6 @@ def load_subsystems(self): # Directory does not exist continue - if not os.listdir(subsystem_dir): - # Directory exists but it is empty - continue - subsystem = pki.server.subsystem.PKISubsystemFactory.create(self, subsystem_name) subsystem.load() diff --git a/base/server/python/pki/server/cli/ca.py b/base/server/python/pki/server/cli/ca.py index fa2cb3fa9dc..366bb8f9480 100644 --- a/base/server/python/pki/server/cli/ca.py +++ b/base/server/python/pki/server/cli/ca.py @@ -49,6 +49,7 @@ class CACLI(pki.cli.CLI): def __init__(self): super().__init__('ca', 'CA management commands') + self.add_module(pki.server.cli.subsystem.SubsystemCreateCLI(self)) self.add_module(pki.server.cli.subsystem.SubsystemDeployCLI(self)) self.add_module(pki.server.cli.subsystem.SubsystemUndeployCLI(self)) self.add_module(pki.server.cli.subsystem.SubsystemRedeployCLI(self)) diff --git a/base/server/python/pki/server/cli/kra.py b/base/server/python/pki/server/cli/kra.py index a2f4e8f1ea1..24d3fdd151a 100644 --- a/base/server/python/pki/server/cli/kra.py +++ b/base/server/python/pki/server/cli/kra.py @@ -47,6 +47,7 @@ class KRACLI(pki.cli.CLI): def __init__(self): super().__init__('kra', 'KRA management commands') + self.add_module(pki.server.cli.subsystem.SubsystemCreateCLI(self)) self.add_module(pki.server.cli.subsystem.SubsystemDeployCLI(self)) self.add_module(pki.server.cli.subsystem.SubsystemUndeployCLI(self)) self.add_module(pki.server.cli.subsystem.SubsystemRedeployCLI(self)) diff --git a/base/server/python/pki/server/cli/ocsp.py b/base/server/python/pki/server/cli/ocsp.py index 19e92cf26bc..515108af41f 100644 --- a/base/server/python/pki/server/cli/ocsp.py +++ b/base/server/python/pki/server/cli/ocsp.py @@ -46,6 +46,7 @@ class OCSPCLI(pki.cli.CLI): def __init__(self): super().__init__('ocsp', 'OCSP management commands') + self.add_module(pki.server.cli.subsystem.SubsystemCreateCLI(self)) self.add_module(pki.server.cli.subsystem.SubsystemDeployCLI(self)) self.add_module(pki.server.cli.subsystem.SubsystemUndeployCLI(self)) self.add_module(pki.server.cli.subsystem.SubsystemRedeployCLI(self)) diff --git a/base/server/python/pki/server/cli/subsystem.py b/base/server/python/pki/server/cli/subsystem.py index 0706b830314..472d00880c5 100644 --- a/base/server/python/pki/server/cli/subsystem.py +++ b/base/server/python/pki/server/cli/subsystem.py @@ -197,6 +197,85 @@ def execute(self, argv): SubsystemCLI.print_subsystem(subsystem) +class SubsystemCreateCLI(pki.cli.CLI): + ''' + Create {subsystem} subsystem + ''' + + help = '''\ + Usage: pki-server {subsystem}-create [OPTIONS] + + -i, --instance Instance ID (default: pki-tomcat) + -v, --verbose Run in verbose mode. + --debug Run in debug mode. + --help Show help message. + ''' # noqa: E501 + + def __init__(self, parent): + super().__init__( + 'create', + inspect.cleandoc(self.__class__.__doc__).format( + subsystem=parent.name.upper())) + + self.parent = parent + + def print_help(self): + print(textwrap.dedent(self.__class__.help).format( + subsystem=self.parent.name)) + + def execute(self, argv): + + try: + opts, _ = getopt.gnu_getopt(argv, 'i:v', [ + 'instance=', + 'verbose', 'debug', 'help']) + + except getopt.GetoptError as e: + logger.error(e) + self.print_help() + sys.exit(1) + + instance_name = 'pki-tomcat' + subsystem_name = self.parent.name + + for o, a in opts: + if o in ('-i', '--instance'): + instance_name = a + + elif o == '--debug': + logging.getLogger().setLevel(logging.DEBUG) + + elif o in ('-v', '--verbose'): + logging.getLogger().setLevel(logging.INFO) + + elif o == '--help': + self.print_help() + sys.exit() + + else: + logger.error('Invalid option: %s', o) + self.print_help() + sys.exit(1) + + instance = pki.server.instance.PKIServerFactory.create(instance_name) + + if not instance.exists(): + raise Exception('Invalid instance: %s' % instance_name) + + instance.load() + + subsystem = instance.get_subsystem(subsystem_name) + if subsystem: + raise Exception('%s subsystem already exists' % subsystem_name.upper()) + + subsystem = pki.server.subsystem.PKISubsystemFactory.create(instance, subsystem_name) + instance.add_subsystem(subsystem) + + subsystem.create(exist_ok=True) + subsystem.create_conf(exist_ok=True) + subsystem.create_logs(exist_ok=True) + + class SubsystemDeployCLI(pki.cli.CLI): def __init__(self, parent): diff --git a/base/server/python/pki/server/cli/tks.py b/base/server/python/pki/server/cli/tks.py index 91dca8b8311..94a689b9933 100644 --- a/base/server/python/pki/server/cli/tks.py +++ b/base/server/python/pki/server/cli/tks.py @@ -46,6 +46,7 @@ class TKSCLI(pki.cli.CLI): def __init__(self): super().__init__('tks', 'TKS management commands') + self.add_module(pki.server.cli.subsystem.SubsystemCreateCLI(self)) self.add_module(pki.server.cli.subsystem.SubsystemDeployCLI(self)) self.add_module(pki.server.cli.subsystem.SubsystemUndeployCLI(self)) self.add_module(pki.server.cli.subsystem.SubsystemRedeployCLI(self)) diff --git a/base/server/python/pki/server/cli/tps.py b/base/server/python/pki/server/cli/tps.py index e7279187e90..e091fec1e63 100644 --- a/base/server/python/pki/server/cli/tps.py +++ b/base/server/python/pki/server/cli/tps.py @@ -46,6 +46,7 @@ class TPSCLI(pki.cli.CLI): def __init__(self): super().__init__('tps', 'TPS management commands') + self.add_module(pki.server.cli.subsystem.SubsystemCreateCLI(self)) self.add_module(pki.server.cli.subsystem.SubsystemDeployCLI(self)) self.add_module(pki.server.cli.subsystem.SubsystemUndeployCLI(self)) self.add_module(pki.server.cli.subsystem.SubsystemRedeployCLI(self)) diff --git a/base/server/python/pki/server/deployment/scriptlets/initialization.py b/base/server/python/pki/server/deployment/scriptlets/initialization.py index 5062bd38467..107553f8b3f 100644 --- a/base/server/python/pki/server/deployment/scriptlets/initialization.py +++ b/base/server/python/pki/server/deployment/scriptlets/initialization.py @@ -156,12 +156,6 @@ def spawn(self, deployer): deployer.verify_subsystem_exists() deployer.mdict['pki_skip_installation'] = "True" - else: - # verify that this type of "subsystem" does NOT yet - # exist for this "instance" - deployer.verify_subsystem_does_not_exist() - # detect and avoid any namespace collisions - deployer.namespace.collision_detection(instance) # verify existence of SENSITIVE configuration file data self.verify_sensitive_data(deployer) # verify existence of MUTUALLY EXCLUSIVE configuration file data diff --git a/base/server/python/pki/server/deployment/scriptlets/subsystem_layout.py b/base/server/python/pki/server/deployment/scriptlets/subsystem_layout.py index 9392e9a4720..d783bdaac7c 100644 --- a/base/server/python/pki/server/deployment/scriptlets/subsystem_layout.py +++ b/base/server/python/pki/server/deployment/scriptlets/subsystem_layout.py @@ -74,10 +74,13 @@ def spawn(self, deployer): 'conf', 'CS.cfg') + # TODO: if the target already exists, merge the source + # into target instead of overwriting the target instance.copyfile( source_cs_cfg, subsystem.cs_conf, - params=deployer.mdict) + params=deployer.mdict, + force=True) # Copy /usr/share/pki//conf/registry.cfg # to /etc/pki///registry.cfg diff --git a/base/server/python/pki/server/subsystem.py b/base/server/python/pki/server/subsystem.py index f154cb1ef40..576eb9dc1b2 100644 --- a/base/server/python/pki/server/subsystem.py +++ b/base/server/python/pki/server/subsystem.py @@ -151,6 +151,25 @@ def create_conf(self, exist_ok=False): # Create /etc/pki// self.instance.makedirs(self.conf_dir, exist_ok=exist_ok) + self.config['cs.type'] = self.type + self.config['instanceId'] = self.instance.name + self.config['passwordClass'] = 'com.netscape.cmsutil.password.PlainPasswordFile' + self.config['passwordFile'] = self.instance.password_conf + + logger.info('Storing subsystem config: %s', self.cs_conf) + self.instance.store_properties(self.cs_conf, self.config) + + # Copy /usr/share/pki//conf/registry.cfg + # to /etc/pki///registry.cfg + + registry_conf = os.path.join( + pki.server.PKIServer.SHARE_DIR, + self.name, + 'conf', + 'registry.cfg') + + self.instance.copy(registry_conf, self.registry_conf) + def create_logs(self, exist_ok=False): # Create /var/log/pki//