diff --git a/.github/workflows/acme-basic-test.yml b/.github/workflows/acme-basic-test.yml index 35f3670fe58..2f6ccbd8c56 100644 --- a/.github/workflows/acme-basic-test.yml +++ b/.github/workflows/acme-basic-test.yml @@ -119,6 +119,7 @@ jobs: # TODO: review permissions cat > expected << EOF + drwxrwx--- pkiuser pkiuser acme lrwxrwxrwx pkiuser pkiuser alias -> /var/lib/pki/pki-tomcat/conf/alias lrwxrwxrwx pkiuser pkiuser bin -> /usr/share/tomcat/bin drwxrwx--- pkiuser pkiuser ca @@ -175,7 +176,7 @@ jobs: # TODO: review permissions cat > expected << EOF - drwxr-xr-x pkiuser pkiuser acme + drwxrwx--- pkiuser pkiuser acme drwxr-x--- pkiuser pkiuser backup drwxrwx--- pkiuser pkiuser ca -rw-rw-r-- pkiuser pkiuser catalina.$DATE.log @@ -188,6 +189,23 @@ jobs: diff expected output + - name: Check ACME base dir + if: always() + run: | + docker exec pki ls -l /var/lib/pki/pki-tomcat/acme \ + | sed \ + -e '/^total/d' \ + -e 's/^\(\S*\) *\S* *\(\S*\) *\(\S*\) *\S* *\S* *\S* *\S* *\(.*\)$/\1 \2 \3 \4/' \ + | tee output + + # TODO: review permissions + cat > expected << EOF + lrwxrwxrwx pkiuser pkiuser conf -> /var/lib/pki/pki-tomcat/conf/acme + lrwxrwxrwx pkiuser pkiuser logs -> /var/lib/pki/pki-tomcat/logs/acme + EOF + + diff expected output + - name: Check ACME conf dir run: | # check file types, owners, and permissions @@ -221,6 +239,11 @@ jobs: run: | docker exec pki cat /etc/pki/pki-tomcat/acme/realm.conf + - name: Check ACME logs dir + if: always() + run: | + docker exec pki ls -l /var/log/pki/pki-tomcat/acme + - name: Check initial ACME accounts run: | docker exec ds ldapsearch \ @@ -664,9 +687,7 @@ jobs: diff expected actual - name: Remove ACME from PKI container - run: | - docker exec pki pki-server acme-undeploy --wait - docker exec pki pki-server acme-remove + run: docker exec pki pkidestroy -s ACME -v - name: Remove CA from PKI container run: docker exec pki pkidestroy -s CA -v @@ -700,6 +721,7 @@ jobs: # TODO: review permissions cat > expected << EOF drwxrwx--- pkiuser pkiuser Catalina + drwxrwx--- pkiuser pkiuser acme drwxrwx--- pkiuser pkiuser alias drwxrwx--- pkiuser pkiuser ca -rw-r--r-- pkiuser pkiuser catalina.policy @@ -729,7 +751,7 @@ jobs: # TODO: review permissions cat > expected << EOF - drwxr-xr-x pkiuser pkiuser acme + drwxrwx--- pkiuser pkiuser acme drwxr-x--- pkiuser pkiuser backup drwxrwx--- pkiuser pkiuser ca -rw-rw-r-- pkiuser pkiuser catalina.$DATE.log diff --git a/.github/workflows/acme-postgresql-test.yml b/.github/workflows/acme-postgresql-test.yml index 235429c44fb..ff7950e34b6 100644 --- a/.github/workflows/acme-postgresql-test.yml +++ b/.github/workflows/acme-postgresql-test.yml @@ -539,9 +539,7 @@ jobs: diff expected actual - name: Remove ACME from PKI container - run: | - docker exec pki pki-server acme-undeploy --wait - docker exec pki pki-server acme-remove + run: docker exec pki pkidestroy -s ACME -v - name: Remove CA from PKI container run: docker exec pki pkidestroy -s CA -v diff --git a/.github/workflows/acme-separate-test.yml b/.github/workflows/acme-separate-test.yml index 227f0084416..5455a0e7f49 100644 --- a/.github/workflows/acme-separate-test.yml +++ b/.github/workflows/acme-separate-test.yml @@ -178,6 +178,7 @@ jobs: # TODO: review permissions cat > expected << EOF + drwxrwx--- pkiuser pkiuser acme lrwxrwxrwx pkiuser pkiuser alias -> /var/lib/pki/pki-tomcat/conf/alias lrwxrwxrwx pkiuser pkiuser bin -> /usr/share/tomcat/bin drwxr-x--- pkiuser pkiuser common @@ -231,6 +232,7 @@ jobs: # TODO: review permissions cat > expected << EOF + drwxrwx--- pkiuser pkiuser acme drwxr-x--- pkiuser pkiuser backup -rw-r--r-- pkiuser pkiuser catalina.$DATE.log -rw-r--r-- pkiuser pkiuser host-manager.$DATE.log @@ -240,6 +242,23 @@ jobs: diff expected output + - name: Check ACME base dir + if: always() + run: | + docker exec acme ls -l /var/lib/pki/pki-tomcat/acme \ + | sed \ + -e '/^total/d' \ + -e 's/^\(\S*\) *\S* *\(\S*\) *\(\S*\) *\S* *\S* *\S* *\S* *\(.*\)$/\1 \2 \3 \4/' \ + | tee output + + # TODO: review permissions + cat > expected << EOF + lrwxrwxrwx pkiuser pkiuser conf -> /var/lib/pki/pki-tomcat/conf/acme + lrwxrwxrwx pkiuser pkiuser logs -> /var/lib/pki/pki-tomcat/logs/acme + EOF + + diff expected output + - name: Check ACME conf dir run: | # check file types, owners, and permissions @@ -273,6 +292,11 @@ jobs: run: | docker exec acme cat /etc/pki/pki-tomcat/acme/realm.conf + - name: Check ACME logs dir + if: always() + run: | + docker exec acme ls -l /var/log/pki/pki-tomcat/acme + - name: Check initial ACME accounts run: | docker exec acmeds ldapsearch \ @@ -724,14 +748,10 @@ jobs: diff expected actual - name: Remove ACME - run: | - docker exec acme pki-server acme-undeploy --wait -v - docker exec acme pki-server acme-remove -v - docker exec acme pki-server stop --wait -v - docker exec acme pki-server remove -v + run: docker exec acme pkidestroy -s ACME -v - name: Remove CA - run: docker exec ca pkidestroy -i pki-tomcat -s CA -v + run: docker exec ca pkidestroy -s CA -v - name: Check ACME server base dir after removal run: | @@ -762,6 +782,7 @@ jobs: # TODO: review permissions cat > expected << EOF drwxr-x--- pkiuser pkiuser Catalina + drwxrwx--- pkiuser pkiuser acme drwxrwx--- pkiuser pkiuser alias -rw-rw---- pkiuser pkiuser catalina.policy lrwxrwxrwx pkiuser pkiuser catalina.properties -> /usr/share/pki/server/conf/catalina.properties @@ -789,7 +810,7 @@ jobs: # TODO: review permissions cat > expected << EOF - drwxr-xr-x pkiuser pkiuser acme + drwxrwx--- pkiuser pkiuser acme drwxr-x--- pkiuser pkiuser backup -rw-r--r-- pkiuser pkiuser catalina.$DATE.log -rw-r--r-- pkiuser pkiuser host-manager.$DATE.log diff --git a/base/server/python/pki/server/__init__.py b/base/server/python/pki/server/__init__.py index fbc8f6159c4..197a615f56e 100644 --- a/base/server/python/pki/server/__init__.py +++ b/base/server/python/pki/server/__init__.py @@ -55,7 +55,7 @@ ETC_SYSTEMD_DIR = '/etc/systemd' LIB_SYSTEMD_DIR = '/lib/systemd' -SUBSYSTEM_TYPES = ['ca', 'kra', 'ocsp', 'tks', 'tps'] +SUBSYSTEM_TYPES = ['ca', 'kra', 'ocsp', 'tks', 'tps', 'acme'] DEFAULT_DIR_MODE = 0o0770 DEFAULT_FILE_MODE = 0o0660 diff --git a/base/server/python/pki/server/cli/acme.py b/base/server/python/pki/server/cli/acme.py index 07a9202d7ed..589e1133289 100644 --- a/base/server/python/pki/server/cli/acme.py +++ b/base/server/python/pki/server/cli/acme.py @@ -100,6 +100,8 @@ def execute(self, argv): subsystem = pki.server.subsystem.ACMESubsystem(instance) subsystem.create(force=force) + subsystem.create_conf(force=force) + subsystem.create_logs(force=force) class ACMERemoveCLI(pki.cli.CLI): @@ -108,9 +110,11 @@ def __init__(self): super().__init__('remove', 'Remove ACME subsystem') def print_help(self): - print('Usage: pki-server acme-remove [OPTIONS] [name]') + print('Usage: pki-server acme-remove [OPTIONS]') print() print(' -i, --instance Instance ID (default: pki-tomcat).') + print(' --remove-conf Remove config folder.') + print(' --remove-logs Remove logs folder.') print(' --force Force removal.') print(' -v, --verbose Run in verbose mode.') print(' --debug Run in debug mode.') @@ -120,9 +124,9 @@ def print_help(self): def execute(self, argv): try: - opts, args = getopt.gnu_getopt(argv, 'i:v', [ + opts, _ = getopt.gnu_getopt(argv, 'i:v', [ 'instance=', - 'force', + 'remove-conf', 'remove-logs', 'force', 'verbose', 'debug', 'help']) except getopt.GetoptError as e: @@ -130,14 +134,21 @@ def execute(self, argv): self.print_help() sys.exit(1) - name = 'acme' instance_name = 'pki-tomcat' + remove_conf = False + remove_logs = False force = False for o, a in opts: if o in ('-i', '--instance'): instance_name = a + elif o == '--remove-conf': + remove_conf = True + + elif o == '--remove-logs': + remove_logs = True + elif o == '--force': force = True @@ -156,9 +167,6 @@ def execute(self, argv): self.print_help() sys.exit(1) - if len(args) > 0: - name = args[0] - instance = pki.server.PKIServerFactory.create(instance_name) if not instance.exists(): @@ -166,9 +174,15 @@ def execute(self, argv): instance.load() - acme_conf_dir = os.path.join(instance.conf_dir, name) - logger.info('Removing %s', acme_conf_dir) - pki.util.rmtree(acme_conf_dir, force=force) + subsystem = pki.server.subsystem.ACMESubsystem(instance) + + if remove_logs: + subsystem.remove_logs(force=force) + + if remove_conf: + subsystem.remove_conf(force=force) + + subsystem.remove(force=force) class ACMEDeployCLI(pki.cli.CLI): diff --git a/base/server/python/pki/server/deployment/__init__.py b/base/server/python/pki/server/deployment/__init__.py index 604c6f9e848..2396d40c3b7 100644 --- a/base/server/python/pki/server/deployment/__init__.py +++ b/base/server/python/pki/server/deployment/__init__.py @@ -5187,6 +5187,8 @@ def create_acme_subsystem(self): subsystem = pki.server.subsystem.ACMESubsystem(self.instance) subsystem.create() + subsystem.create_conf() + subsystem.create_logs() return subsystem @@ -5371,6 +5373,49 @@ def spawn_acme(self): self.deploy_acme_webapp(subsystem) + def undeploy_acme_webapp(self, subsystem): + ''' + See also pki-server acme-undeploy. + ''' + + logger.info('Undeploying ACME webapp') + + subsystem.disable(wait=True) + + def remove_acme_subsystem(self, subsystem): + ''' + See also pki-server acme-remove. + ''' + + logger.info('Removing ACME subsystem') + + if self.remove_logs: + subsystem.remove_logs(force=self.force) + + if self.remove_conf: + subsystem.remove_conf(force=self.force) + + subsystem.remove(force=self.force) + + def destroy_acme(self): + + subsystem = self.instance.remove_subsystem('acme') + + self.undeploy_acme_webapp(subsystem) + self.remove_acme_subsystem(subsystem) + + if len(self.instance.get_subsystems()) == 0: + # if this is the last subsystem, stop the server + self.instance.stop( + wait=True, + max_wait=self.startup_timeout, + timeout=self.request_timeout) + + # then remove the server + self.instance.remove( + remove_conf=self.remove_conf, + remove_logs=self.remove_logs) + def create_est_subsystem(self): ''' See also pki-server est-create. @@ -5567,6 +5612,10 @@ def destroy(self): print('Uninstalling ' + self.subsystem_type + ' from ' + self.instance.base_dir + '.') + if self.subsystem_type == 'ACME': + self.destroy_acme() + return + scriptlet = pki.server.deployment.scriptlets.initialization.PkiScriptlet() scriptlet.deployer = self scriptlet.instance = self.instance diff --git a/base/server/python/pki/server/subsystem.py b/base/server/python/pki/server/subsystem.py index 99801a81870..3deaff89695 100644 --- a/base/server/python/pki/server/subsystem.py +++ b/base/server/python/pki/server/subsystem.py @@ -2768,28 +2768,63 @@ def realm_conf(self): def create(self, exist_ok=False, force=False): - self.instance.makedirs(self.conf_dir, exist_ok=exist_ok) + # Create /var/lib/pki// + self.instance.makedirs(self.base_dir, exist_ok=exist_ok, force=force) + + def create_conf(self, exist_ok=False, force=False): + + # Create /etc/pki// + self.instance.makedirs(self.conf_dir, exist_ok=exist_ok, force=force) + + # Link /var/lib/pki///conf + # to /etc/pki// + + conf_link = os.path.join(self.base_dir, 'conf') + self.instance.symlink( + self.conf_dir, + conf_link, + exist_ok=exist_ok) default_conf_dir = os.path.join(pki.server.PKIServer.SHARE_DIR, 'acme', 'conf') + # Copy /usr/share/pki/acme/conf/database.conf + # to /etc/pki///database.conf self.instance.copy( os.path.join(default_conf_dir, 'database.conf'), self.database_conf, exist_ok=exist_ok, force=force) + # Copy /usr/share/pki/acme/conf/issuer.conf + # to /etc/pki///issuer.conf self.instance.copy( os.path.join(default_conf_dir, 'issuer.conf'), self.issuer_conf, exist_ok=exist_ok, force=force) + # Copy /usr/share/pki/acme/conf/realm.conf + # to /etc/pki///realm.conf self.instance.copy( os.path.join(default_conf_dir, 'realm.conf'), self.realm_conf, exist_ok=exist_ok, force=force) + def create_logs(self, exist_ok=False, force=False): + + # Create /var/log/pki// + self.instance.makedirs(self.logs_dir, exist_ok=exist_ok, force=force) + + # Link /var/lib/pki///logs + # to /var/log/pki// + + logs_link = os.path.join(self.base_dir, 'logs') + self.instance.symlink( + self.logs_dir, + logs_link, + exist_ok=exist_ok) + def get_database_config(self, database_type=None): template_dir = os.path.join(pki.server.PKIServer.SHARE_DIR, 'acme', 'database') @@ -2856,6 +2891,13 @@ def update_realm_config(self, config): logger.info('Updating %s', self.realm_conf) self.instance.store_properties(self.realm_conf, config) + def save(self): + + # override PKISubsystem.save() since ACME does not use CS.cfg + # and registry.cfg + + pass + class ESTSubsystem(PKISubsystem): @@ -3029,4 +3071,7 @@ def create(cls, instance, name): if name == 'tps': return TPSSubsystem(instance) + if name == 'acme': + return ACMESubsystem(instance) + return PKISubsystem(instance, name)