From c6e1bb12ec0c58a97b2dd44f424a9e316189e7d8 Mon Sep 17 00:00:00 2001
From: Matthew Harmsen <mharmsen@redhat.com>
Date: Sat, 28 Jul 2012 18:59:30 -0700
Subject: [PATCH] PKI Deployment Scriptlets

* TRAC Ticket #263 - Dogtag 10: Fix 'pkidestroy' problem of sporadically "not"
  removing "/etc/sysconfig/{pki_instance_id}" . . .
* TRAC Ticket #264 - Dogtag 10: Enable various other subsystems for
  configuration . . .
* TRAC Ticket #261 - Dogtag 10: Revisit command-line options of 'pkispawn' and
  'pkidestroy' . . .
* TRAC Ticket #268 - Dogtag 10: Create a parameter for optional restart of
  configured PKI instance . . .
* TRAC Ticket #270 - Dogtag 10: Add missing parameters to
  'pkideployment.cfg' . . .
* TRAC Ticket #265 - Dogtag 10: Provide configurable options for PKI client
  information . . .
* TRAC Ticket #275 - Dogtag 10: Add debug information (comments) to Tomcat 7
  "logging.properties"
* TRAC Ticket #276 - Dogtag 10: Relocate all 'pin' data to the 'sensitive'
  dictionary
* TRAC Ticket #277 - Dogtag 10: Create an 'archive' for 'manifest' and
  'pkideployment.cfg' files
---
 base/common/shared/conf/logging.properties         |   15 +
 base/deploy/config/pkideployment.cfg               |   20 +-
 base/deploy/src/pkidestroy                         |   18 -
 base/deploy/src/pkispawn                           |   29 --
 base/deploy/src/scriptlets/configuration.jy        |   58 +--
 base/deploy/src/scriptlets/configuration.py        |   30 +-
 base/deploy/src/scriptlets/finalization.py         |   82 ++-
 .../deploy/src/scriptlets/infrastructure_layout.py |    7 -
 base/deploy/src/scriptlets/initialization.py       |   18 +-
 base/deploy/src/scriptlets/instance_layout.py      |    4 +
 base/deploy/src/scriptlets/pkiconfig.py            |   21 +-
 base/deploy/src/scriptlets/pkihelper.py            |  202 +++++++-
 base/deploy/src/scriptlets/pkijython.py            |   25 +-
 base/deploy/src/scriptlets/pkimanifest.py          |    2 -
 base/deploy/src/scriptlets/pkimessages.py          |   59 ++-
 base/deploy/src/scriptlets/pkiparser.py            |  537 ++++++++++----------
 base/deploy/src/scriptlets/security_databases.py   |    9 +-
 base/deploy/src/scriptlets/subsystem_layout.py     |    6 +
 18 files changed, 661 insertions(+), 481 deletions(-)

diff --git a/base/common/shared/conf/logging.properties b/base/common/shared/conf/logging.properties
index f1fb462..dfdc0a4 100644
--- a/base/common/shared/conf/logging.properties
+++ b/base/common/shared/conf/logging.properties
@@ -28,6 +28,21 @@ handlers = 1catalina.org.apache.juli.FileHandler, 2localhost.org.apache.juli.Fil
 # Describes specific configuration info for Handlers.
 ############################################################
 
+# Change the following settings to allow for more granular debugging:
+#
+#     * 1catalina.org.apache.juli.FileHandler.level = ALL
+#     * 2localhost.org.apache.juli.FileHandler.level = ALL
+#
+# and add the following lines to the end of this file:
+#
+#     * org.apache.catalina.loader.level = FINEST
+#     * org.apache.catalina.loader.WebappClassLoader.level = FINEST
+#     * org.apache.catalina.loader.StandardClassLoader.level = FINEST
+#     * com.netscape.cms.servlet.base.level = FINEST
+#     * com.netscape.cms.servlet.base.CMSStartServlet.level = FINEST
+#     * java.net.URLClassLoader.level = FINEST
+#
+
 1catalina.org.apache.juli.FileHandler.level = FINE
 1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
 1catalina.org.apache.juli.FileHandler.prefix = catalina.
diff --git a/base/deploy/config/pkideployment.cfg b/base/deploy/config/pkideployment.cfg
index d0acd7f..7e91f87 100644
--- a/base/deploy/config/pkideployment.cfg
+++ b/base/deploy/config/pkideployment.cfg
@@ -10,10 +10,12 @@
 [Sensitive]
 pki_admin_password=
 pki_backup_password=
+pki_client_database_password=
 pki_client_pkcs12_password=
 pki_clone_pkcs12_password=
 pki_ds_password=
 pki_security_domain_password=
+pki_token_password=
 ###############################################################################
 ##  'Common' Data:                                                           ##
 ##                                                                           ##
@@ -44,6 +46,10 @@ pki_audit_signing_subject_dn=
 pki_audit_signing_token=
 pki_backup_file=
 pki_backup_keys=False
+pki_client_database_path=
+pki_client_database_purge=True
+pki_client_path=
+pki_client_pkcs12_path=
 pki_ds_base_dn=
 pki_ds_bind_dn=cn=Directory Manager
 pki_ds_database=
@@ -53,6 +59,7 @@ pki_ds_ldaps_port=636
 pki_ds_remove_data=True
 pki_ds_secure_connection=False
 pki_group=pkiuser
+pki_restart_configured_instance=True
 pki_security_domain_hostname=
 pki_security_domain_https_port=8443
 pki_security_domain_name=
@@ -69,6 +76,7 @@ pki_subsystem_key_type=rsa
 pki_subsystem_nickname=
 pki_subsystem_subject_dn=
 pki_subsystem_token=
+pki_token_name=internal
 pki_user=pkiuser
 ###############################################################################
 ##  'Apache' Data:                                                           ##
@@ -99,12 +107,16 @@ pki_https_port=443
 [Tomcat]
 pki_ajp_port=8009
 pki_clone=False
+pki_clone_pkcs12_path=
+pki_clone_replication_security=None
+pki_clone_uri=
 pki_enable_java_debugger=False
+pki_enable_proxy=False
 pki_http_port=8080
 pki_https_port=8443
 pki_instance_name=pki-tomcat
-pki_proxy_http_port=
-pki_proxy_https_port=
+pki_proxy_http_port=80
+pki_proxy_https_port=443
 pki_security_manager=false
 pki_tomcat_server_port=8005
 ###############################################################################
@@ -132,6 +144,10 @@ pki_ca_signing_signing_algorithm=SHA256withRSA
 pki_ca_signing_subject_dn=
 pki_ca_signing_token=
 pki_external=False
+pki_external_ca_cert_chain_path=
+pki_external_ca_cert_path=
+pki_external_csr_path=
+pki_external_step_two=False
 pki_ocsp_signing_key_algorithm=SHA256withRSA
 pki_ocsp_signing_key_size=2048
 pki_ocsp_signing_key_type=rsa
diff --git a/base/deploy/src/pkidestroy b/base/deploy/src/pkidestroy
index 1e0f020..165ccb0 100755
--- a/base/deploy/src/pkidestroy
+++ b/base/deploy/src/pkidestroy
@@ -30,9 +30,7 @@ try:
     import logging
     import os
     import pprint
-    import random
     import socket
-    import string
     import struct
     import subprocess
     import time
@@ -139,22 +137,6 @@ def main(argv):
         config.pki_log.debug(pp.pformat(config.pki_subsystem_dict),
                              extra=config.PKI_INDENTATION_LEVEL_0)
 
-    # Override PKI configuration file values with 'custom' command-line values.
-    if not config.custom_pki_admin_domain_name is None:
-        config.pki_common_dict['pki_admin_domain_name'] =\
-            config.custom_pki_admin_domain_name
-    if not config.custom_pki_instance_name is None:
-        config.pki_web_server_dict['pki_instance_name'] =\
-            config.custom_pki_instance_name
-    if not config.custom_pki_http_port is None:
-        config.pki_web_server_dict['pki_http_port'] =\
-            config.custom_pki_http_port
-    if not config.custom_pki_https_port is None:
-        config.pki_web_server_dict['pki_https_port'] =\
-            config.custom_pki_https_port
-    if not config.custom_pki_ajp_port is None:
-        config.pki_web_server_dict['pki_ajp_port'] =\
-            config.custom_pki_ajp_port
     # NEVER print out 'sensitive' name/value pairs!!!
     config.pki_log.debug(log.PKI_DICTIONARY_COMMON,
                          extra=config.PKI_INDENTATION_LEVEL_0)
diff --git a/base/deploy/src/pkispawn b/base/deploy/src/pkispawn
index 75c1967..795c579 100755
--- a/base/deploy/src/pkispawn
+++ b/base/deploy/src/pkispawn
@@ -30,9 +30,7 @@ try:
     import logging
     import os
     import pprint
-    import random
     import socket
-    import string
     import struct
     import subprocess
     import time
@@ -90,17 +88,6 @@ def main(argv):
         print log.PKI_SUBPROCESS_ERROR_1 % exc
         sys.exit(1)
 
-    # Generate random 'pin's for use as security database passwords
-    pin_low  = 100000000000
-    pin_high = 999999999999
-    config.pki_pin = random.randint(pin_low, pin_high)
-    config.pki_client_pin = random.randint(pin_low, pin_high)
-
-    # Generate a one-time pin to be used prior to configuration
-    config.pki_one_time_pin =\
-        ''.join(random.choice(string.ascii_letters + string.digits)\
-        for x in range(20))
-
     # Initialize 'pretty print' for objects
     pp = pprint.PrettyPrinter(indent=4)
 
@@ -168,22 +155,6 @@ def main(argv):
         config.pki_log.debug(pp.pformat(config.pki_subsystem_dict),
                              extra=config.PKI_INDENTATION_LEVEL_0)
 
-    # Override PKI configuration file values with 'custom' command-line values.
-    if not config.custom_pki_admin_domain_name is None:
-        config.pki_common_dict['pki_admin_domain_name'] =\
-            config.custom_pki_admin_domain_name
-    if not config.custom_pki_instance_name is None:
-        config.pki_web_server_dict['pki_instance_name'] =\
-            config.custom_pki_instance_name
-    if not config.custom_pki_http_port is None:
-        config.pki_web_server_dict['pki_http_port'] =\
-            config.custom_pki_http_port
-    if not config.custom_pki_https_port is None:
-        config.pki_web_server_dict['pki_https_port'] =\
-            config.custom_pki_https_port
-    if not config.custom_pki_ajp_port is None:
-        config.pki_web_server_dict['pki_ajp_port'] =\
-            config.custom_pki_ajp_port
     # NEVER print out 'sensitive' name/value pairs!!!
     config.pki_log.debug(log.PKI_DICTIONARY_COMMON,
                          extra=config.PKI_INDENTATION_LEVEL_0)
diff --git a/base/deploy/src/scriptlets/configuration.jy b/base/deploy/src/scriptlets/configuration.jy
index 2e72f40..e7dd214 100644
--- a/base/deploy/src/scriptlets/configuration.jy
+++ b/base/deploy/src/scriptlets/configuration.jy
@@ -19,12 +19,16 @@ from java.lang import System as javasystem
 def main(argv):
     rv = 0
 
-    # Establish 'master' as the PKI jython dictionary
+    # Establish 'master' and 'sensitive' as two separate PKI jython dictionaries
     master = dict()
+    sensitive = dict()
 
     # Import the master dictionary from 'pkispawn'
     master = pickle.loads(argv[1])
 
+    # Import the sensitive data dictionary from 'pkispawn'
+    sensitive = pickle.loads(argv[2])
+
     # Optionally enable a java debugger (e. g. - 'eclipse'):
     if config.str2bool(master['pki_enable_java_debugger']):
         config.wait_to_attach_an_external_java_debugger()
@@ -116,54 +120,18 @@ def main(argv):
                        log.PKI_JYTHON_NOT_YET_IMPLEMENTED)
                 return self.rv
             else:
+                # CA
                 data = jyutil.rest_client.construct_pki_configuration_data(
-                           master, token)
-        elif master['pki_subsystem'] == "KRA":
-            if config.str2bool(master['pki_clone']):
-                print "%s '%s %s' %s" %\
-                      (log.PKI_JYTHON_INDENTATION_2,
-                       log.PKI_JYTHON_CLONED_PKI_SUBSYSTEM,
-                       master['pki_subsystem'],
-                       log.PKI_JYTHON_NOT_YET_IMPLEMENTED)
-                return self.rv
-            else:
-                print "%s '%s' %s" %\
-                      (log.PKI_JYTHON_INDENTATION_2,
-                       master['pki_subsystem'],
-                       log.PKI_JYTHON_NOT_YET_IMPLEMENTED)
-                return self.rv
-        elif master['pki_subsystem'] == "OCSP":
-            if config.str2bool(master['pki_clone']):
-                print "%s '%s %s' %s" %\
-                      (log.PKI_JYTHON_INDENTATION_2,
-                       log.PKI_JYTHON_CLONED_PKI_SUBSYSTEM,
-                       master['pki_subsystem'],
-                       log.PKI_JYTHON_NOT_YET_IMPLEMENTED)
-                return self.rv
-            else:
-                print "%s '%s' %s" %\
-                      (log.PKI_JYTHON_INDENTATION_2,
-                       master['pki_subsystem'],
-                       log.PKI_JYTHON_NOT_YET_IMPLEMENTED)
-                return self.rv
-        elif master['pki_subsystem'] == "TKS":
-            if config.str2bool(master['pki_clone']):
-                print "%s '%s %s' %s" %\
-                      (log.PKI_JYTHON_INDENTATION_2,
-                       log.PKI_JYTHON_CLONED_PKI_SUBSYSTEM,
-                       master['pki_subsystem'],
-                       log.PKI_JYTHON_NOT_YET_IMPLEMENTED)
-                return self.rv
-            else:
-                print "%s '%s' %s" %\
-                      (log.PKI_JYTHON_INDENTATION_2,
-                       master['pki_subsystem'],
-                       log.PKI_JYTHON_NOT_YET_IMPLEMENTED)
-                return self.rv
+                           master, sensitive, token)
+        else:
+            # KRA, OCSP, or TKS
+            data = jyutil.rest_client.construct_pki_configuration_data(
+                       master, sensitive, token)
 
     # Formulate PKI Subsystem Configuration Data Response
     jyutil.rest_client.configure_pki_data(data,
-                                          master)
+                                          master,
+                                          sensitive)
 
 
 if __name__ == "__main__":
diff --git a/base/deploy/src/scriptlets/configuration.py b/base/deploy/src/scriptlets/configuration.py
index 742a4ec..a3b2505 100644
--- a/base/deploy/src/scriptlets/configuration.py
+++ b/base/deploy/src/scriptlets/configuration.py
@@ -22,6 +22,7 @@
 # PKI Deployment Imports
 import pkiconfig as config
 from pkiconfig import pki_master_dict as master
+from pkiconfig import pki_sensitive_dict as sensitive
 import pkihelper as util
 import pkimessages as log
 import pkiscriptlet
@@ -46,7 +47,7 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
             # allowing 'certutil' to generate the security databases
             util.password.create_password_conf(
                 master['pki_client_password_conf'],
-                master['pki_client_pin'], pin_sans_token=True)
+                sensitive['pki_client_database_password'], pin_sans_token=True)
             util.file.modify(master['pki_client_password_conf'],
                              uid=0, gid=0)
             # Similarly, create a simple password file containing the
@@ -54,8 +55,7 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
             # into a PKCS #12 file
             util.password.create_client_pkcs12_password_conf(
                 master['pki_client_pkcs12_password_conf'])
-            util.file.modify(master['pki_client_pkcs12_password_conf'],
-                             uid=0, gid=0)
+            util.file.modify(master['pki_client_pkcs12_password_conf'])
             util.directory.create(master['pki_client_database_path'],
                                   uid=0, gid=0)
             util.certutil.create_security_databases(
@@ -73,7 +73,7 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
             # allowing 'certutil' to generate the security databases
             util.password.create_password_conf(
                 master['pki_client_password_conf'],
-                master['pki_client_pin'], pin_sans_token=True)
+                sensitive['pki_client_database_password'], pin_sans_token=True)
             # Similarly, create a simple password file containing the
             # PKCS #12 password used when exporting the "Admin Certificate"
             # into a PKCS #12 file
@@ -130,10 +130,12 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
     def respawn(self):
         config.pki_log.info(log.CONFIGURATION_RESPAWN_1, __name__,
                             extra=config.PKI_INDENTATION_LEVEL_1)
-        util.file.modify(master['pki_client_password_conf'],
-                         uid=0, gid=0)
-        util.file.modify(master['pki_client_pkcs12_password_conf'],
-                         uid=0, gid=0)
+        if util.file.exists(master['pki_client_password_conf']):
+            util.file.modify(master['pki_client_password_conf'],
+                             uid=0, gid=0)
+        if util.file.exists(master['pki_client_pkcs12_password_conf']):
+            util.file.modify(master['pki_client_pkcs12_password_conf'],
+                             uid=0, gid=0)
         # ALWAYS Restart this Apache/Tomcat PKI Process
         util.systemd.restart()
         return self.rv
@@ -144,20 +146,24 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
         if not config.pki_dry_run_flag:
             if master['pki_subsystem'] in config.PKI_APACHE_SUBSYSTEMS and\
                util.instance.apache_instances() == 1:
-                util.directory.delete(master['pki_client_path'])
+                if util.directory.exists(master['pki_client_path']):
+                    util.directory.delete(master['pki_client_path'])
                 util.symlink.delete(master['pki_systemd_service_link'])
             elif master['pki_subsystem'] in config.PKI_TOMCAT_SUBSYSTEMS and\
                  util.instance.tomcat_instances() == 1:
-                util.directory.delete(master['pki_client_path'])
+                if util.directory.exists(master['pki_client_path']):
+                    util.directory.delete(master['pki_client_path'])
                 util.symlink.delete(master['pki_systemd_service_link'])
         else:
             # ALWAYS display correct information (even during dry_run)
             if master['pki_subsystem'] in config.PKI_APACHE_SUBSYSTEMS and\
                util.instance.apache_instances() == 0:
-                util.directory.delete(master['pki_client_path'])
+                if util.directory.exists(master['pki_client_path']):
+                    util.directory.delete(master['pki_client_path'])
                 util.symlink.delete(master['pki_systemd_service_link'])
             elif master['pki_subsystem'] in config.PKI_TOMCAT_SUBSYSTEMS and\
                  util.instance.tomcat_instances() == 0:
-                util.directory.delete(master['pki_client_path'])
+                if util.directory.exists(master['pki_client_path']):
+                    util.directory.delete(master['pki_client_path'])
                 util.symlink.delete(master['pki_systemd_service_link'])
         return self.rv
diff --git a/base/deploy/src/scriptlets/finalization.py b/base/deploy/src/scriptlets/finalization.py
index bceec67..1ccf2e8 100644
--- a/base/deploy/src/scriptlets/finalization.py
+++ b/base/deploy/src/scriptlets/finalization.py
@@ -37,21 +37,38 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
                             extra=config.PKI_INDENTATION_LEVEL_1)
         # Save a copy of the configuration file used by this process
         # (which may be used later by 'pkidestroy')
-        util.file.copy(config.pkideployment_cfg,
-                       master['pki_subsystem_registry_path'] +\
-                       "/" + config.PKI_DEPLOYMENT_DEFAULT_CONFIGURATION_FILE)
-        # Save a timestamped copy of the installation manifest file
-        filename = master['pki_subsystem_registry_path'] + "/" +\
-                   "spawn" + "_" + "manifest" + "." +\
-                   master['pki_timestamp'] + "." + "csv"
-        config.pki_log.info(log.PKI_MANIFEST_MESSAGE_1, filename,
+        util.file.copy(master['pki_deployment_cfg'],
+                       master['pki_deployment_cfg_replica'])
+        # Also, for debugging/auditing purposes, save a timestamped copy of
+        # this configuration file in the subsystem archive
+        util.file.copy(master['pki_deployment_cfg_replica'],
+                       master['pki_deployment_cfg_spawn_archive'])
+        # Save a copy of the installation manifest file
+        config.pki_log.info(log.PKI_MANIFEST_MESSAGE_1, master['pki_manifest'],
                             extra=config.PKI_INDENTATION_LEVEL_2)
         # for record in manifest.database:
         #     print tuple(record)
         if not config.pki_dry_run_flag:
-            manifest.file.register(filename)
+            manifest.file.register(master['pki_manifest'])
             manifest.file.write()
-            util.file.modify(filename, silent=True)
+            util.file.modify(master['pki_manifest'], silent=True)
+        # Also, for debugging/auditing purposes, save a timestamped copy of
+        # this installation manifest file
+        util.file.copy(master['pki_manifest'],
+                       master['pki_manifest_spawn_archive'])
+        # Optionally, programmatically 'restart' the configured PKI instance
+        if config.str2bool(master['pki_restart_configured_instance']):
+            util.systemd.restart()
+        # Optionally, 'purge' the entire temporary client infrastructure
+        # including the client NSS security databases and password files
+        #
+        #     WARNING:  If the PKCS #12 file containing the Admin Cert was
+        #               placed under this infrastructure, it may accidentally
+        #               be deleted!
+        #
+        if config.str2bool(master['pki_client_database_purge']):
+            if util.directory.exists(master['pki_client_path']):
+                util.directory.delete(master['pki_client_path'])
         # Log final process messages
         config.pki_log.info(log.PKISPAWN_END_MESSAGE_2,
                             master['pki_subsystem'],
@@ -66,22 +83,39 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
                             extra=config.PKI_INDENTATION_LEVEL_1)
         # Save a copy of the configuration file used by this process
         # (which may be used later by 'pkidestroy')
-        util.file.copy(config.pkideployment_cfg,
-                       master['pki_subsystem_registry_path'] +\
-                       "/" + config.PKI_DEPLOYMENT_DEFAULT_CONFIGURATION_FILE,
+        util.file.copy(master['pki_deployment_cfg'],
+                       master['pki_deployment_cfg_replica'],
                        overwrite_flag=True)
-        # Save a timestamped copy of the updated manifest file
-        filename = master['pki_subsystem_registry_path'] + "/" +\
-                   "respawn" + "_" + "manifest" + "." +\
-                   master['pki_timestamp'] + "." + "csv"
-        config.pki_log.info(log.PKI_MANIFEST_MESSAGE_1, filename,
+        # Also, for debugging/auditing purposes, save a timestamped copy of
+        # this configuration file in the subsystem archive
+        util.file.copy(master['pki_deployment_cfg_replica'],
+                       master['pki_deployment_cfg_respawn_archive'])
+        # Save a copy of the updated manifest file
+        config.pki_log.info(log.PKI_MANIFEST_MESSAGE_1, master['pki_manifest'],
                             extra=config.PKI_INDENTATION_LEVEL_2)
         # for record in manifest.database:
         #     print tuple(record)
         if not config.pki_dry_run_flag:
-            manifest.file.register(filename)
+            manifest.file.register(master['pki_manifest'])
             manifest.file.write()
-            util.file.modify(filename, silent=True)
+            util.file.modify(master['pki_manifest'], silent=True)
+        # Also, for debugging/auditing purposes, save a timestamped copy of
+        # this installation manifest file
+        util.file.copy(master['pki_manifest'],
+                       master['pki_manifest_respawn_archive'])
+        # Optionally, programmatically 'restart' the configured PKI instance
+        if config.str2bool(master['pki_restart_configured_instance']):
+            util.systemd.restart()
+        # Optionally, 'purge' the entire temporary client infrastructure
+        # including the client NSS security databases and password files
+        #
+        #     WARNING:  If the PKCS #12 file containing the Admin Cert was
+        #               placed under this infrastructure, it may accidentally
+        #               be deleted!
+        #
+        if config.str2bool(master['pki_client_database_purge']):
+            if util.directory.exists(master['pki_client_path']):
+                util.directory.delete(master['pki_client_path'])
         # Log final process messages
         config.pki_log.info(log.PKIRESPAWN_END_MESSAGE_2,
                             master['pki_subsystem'],
@@ -94,10 +128,6 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
     def destroy(self):
         config.pki_log.info(log.FINALIZATION_DESTROY_1, __name__,
                             extra=config.PKI_INDENTATION_LEVEL_1)
-        config.pki_log.info(log.PKIDESTROY_END_MESSAGE_2,
-                            master['pki_subsystem'],
-                            master['pki_instance_id'],
-                            extra=config.PKI_INDENTATION_LEVEL_0)
         if not config.pki_dry_run_flag:
             util.file.modify(master['pki_destroy_log'], silent=True)
         # Start this Apache/Tomcat PKI Process
@@ -116,4 +146,8 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
             elif master['pki_subsystem'] in config.PKI_TOMCAT_SUBSYSTEMS and\
                  util.instance.tomcat_instances() >= 0:
                 util.systemd.start()
+        config.pki_log.info(log.PKIDESTROY_END_MESSAGE_2,
+                            master['pki_subsystem'],
+                            master['pki_instance_id'],
+                            extra=config.PKI_INDENTATION_LEVEL_0)
         return self.rv
diff --git a/base/deploy/src/scriptlets/infrastructure_layout.py b/base/deploy/src/scriptlets/infrastructure_layout.py
index d5ce233..5e573d2 100644
--- a/base/deploy/src/scriptlets/infrastructure_layout.py
+++ b/base/deploy/src/scriptlets/infrastructure_layout.py
@@ -82,10 +82,6 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
                     util.directory.delete(master['pki_configuration_path'])
                 # remove top-level infrastructure registry
                 util.directory.delete(master['pki_registry_path'])
-                if master['pki_subsystem'] in config.PKI_TOMCAT_SUBSYSTEMS:
-                    util.file.delete(
-                        master['pki_target_tomcat_conf_instance_id'])
-
         else:
             # ALWAYS display correct information (even during dry_run)
             if master['pki_subsystem'] in config.PKI_SUBSYSTEMS and\
@@ -102,7 +98,4 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
                     util.directory.delete(master['pki_configuration_path'])
                 # remove top-level infrastructure registry
                 util.directory.delete(master['pki_registry_path'])
-                if master['pki_subsystem'] in config.PKI_TOMCAT_SUBSYSTEMS:
-                    util.file.delete(
-                        master['pki_target_tomcat_conf_instance_id'])
         return self.rv
diff --git a/base/deploy/src/scriptlets/initialization.py b/base/deploy/src/scriptlets/initialization.py
index da1a934..f158592 100644
--- a/base/deploy/src/scriptlets/initialization.py
+++ b/base/deploy/src/scriptlets/initialization.py
@@ -32,8 +32,6 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
     rv = 0
 
     def spawn(self):
-        # detect and avoid any namespace collisions
-        util.namespace.collision_detection()
         # begin official logging
         config.pki_log.info(log.PKISPAWN_BEGIN_MESSAGE_2,
                             master['pki_subsystem'],
@@ -41,6 +39,11 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
                             extra=config.PKI_INDENTATION_LEVEL_0)
         config.pki_log.info(log.INITIALIZATION_SPAWN_1, __name__,
                             extra=config.PKI_INDENTATION_LEVEL_1)
+        # verify that this type of "subsystem" does NOT yet
+        # exist for this "instance"
+        util.instance.verify_subsystem_does_not_exist()
+        # detect and avoid any namespace collisions
+        util.namespace.collision_detection()
         # initialize 'uid' and 'gid'
         util.identity.add_uid_and_gid(master['pki_user'], master['pki_group'])
         # establish 'uid' and 'gid'
@@ -50,6 +53,8 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
         util.configuration_file.verify_sensitive_data()
         # verify existence of MUTUALLY EXCLUSIVE configuration file data
         util.configuration_file.verify_mutually_exclusive_data()
+        # verify existence of PREDEFINED configuration file data
+        util.configuration_file.verify_predefined_configuration_file_data()
         # verify selinux context of selected ports
         util.configuration_file.populate_non_default_ports()
         util.configuration_file.verify_selinux_ports()
@@ -63,6 +68,9 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
                             extra=config.PKI_INDENTATION_LEVEL_0)
         config.pki_log.info(log.INITIALIZATION_RESPAWN_1, __name__,
                             extra=config.PKI_INDENTATION_LEVEL_1)
+        # verify that this type of "subsystem" currently EXISTS
+        # for this "instance"
+        util.instance.verify_subsystem_exists()
         # establish 'uid' and 'gid'
         util.identity.set_uid(master['pki_user'])
         util.identity.set_gid(master['pki_group'])
@@ -76,6 +84,12 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
                             extra=config.PKI_INDENTATION_LEVEL_0)
         config.pki_log.info(log.INITIALIZATION_DESTROY_1, __name__,
                             extra=config.PKI_INDENTATION_LEVEL_1)
+        # verify that this type of "subsystem" currently EXISTS
+        # for this "instance"
+        util.instance.verify_subsystem_exists()
+        # verify that the command-line parameters match the values
+        # that are present in the corresponding configuration file
+        util.configuration_file.verify_command_matches_configuration_file()
         # establish 'uid' and 'gid'
         util.identity.set_uid(master['pki_user'])
         util.identity.set_gid(master['pki_group'])
diff --git a/base/deploy/src/scriptlets/instance_layout.py b/base/deploy/src/scriptlets/instance_layout.py
index 7829e24..1e5cb2b 100644
--- a/base/deploy/src/scriptlets/instance_layout.py
+++ b/base/deploy/src/scriptlets/instance_layout.py
@@ -256,6 +256,8 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
                 util.directory.delete(master['pki_instance_configuration_path'])
                 # remove Tomcat instance registry
                 util.directory.delete(master['pki_instance_type_registry_path'])
+                # remove PKI 'tomcat.conf' instance file
+                util.file.delete(master['pki_target_tomcat_conf_instance_id'])
         else:
             # ALWAYS display correct information (even during dry_run)
             if master['pki_subsystem'] in config.PKI_APACHE_SUBSYSTEMS and\
@@ -283,4 +285,6 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
                 util.directory.delete(master['pki_instance_configuration_path'])
                 # remove Tomcat instance registry
                 util.directory.delete(master['pki_instance_type_registry_path'])
+                # remove PKI 'tomcat.conf' instance file
+                util.file.delete(master['pki_target_tomcat_conf_instance_id'])
         return self.rv
diff --git a/base/deploy/src/scriptlets/pkiconfig.py b/base/deploy/src/scriptlets/pkiconfig.py
index 6418322..47ed16f 100644
--- a/base/deploy/src/scriptlets/pkiconfig.py
+++ b/base/deploy/src/scriptlets/pkiconfig.py
@@ -107,28 +107,25 @@ pki_install_time = None
 pki_timestamp = None
 pki_architecture = None
 pki_hostname = None
-pki_pin = None
-pki_client_pin = None
-pki_one_time_pin = None
 
 
+# PKI Deployment Command-Line Variables
+pki_deployment_executable = None
+
 # PKI Deployment "Mandatory" Command-Line Variables
 pki_subsystem = None
 #     'pkispawn' ONLY
-pkideployment_cfg = "/usr/share/pki/deployment/config/pkideployment.cfg"
+pkideployment_cfg = None
+#     'pkidestroy' ONLY
+pki_deployed_instance_name = None
 
 # PKI Deployment "Optional" Command-Line Variables
 pki_dry_run_flag = False
-pki_root_prefix = None
+#     'pkispawn' ONLY
 pki_update_flag = False
 
-# PKI Deployment "Custom" Command-Line Variables
-custom_pki_admin_domain_name = None
-custom_pki_instance_name = None
-#     'pkispawn' ONLY
-custom_pki_http_port = None
-custom_pki_https_port = None
-custom_pki_ajp_port = None
+# PKI Deployment "Test" Command-Line Variables
+pki_root_prefix = None
 
 
 # PKI Deployment Helper Functions
diff --git a/base/deploy/src/scriptlets/pkihelper.py b/base/deploy/src/scriptlets/pkihelper.py
index 31877bf..cc6d0e5 100644
--- a/base/deploy/src/scriptlets/pkihelper.py
+++ b/base/deploy/src/scriptlets/pkihelper.py
@@ -421,8 +421,9 @@ class configuration_file:
             if not sensitive.has_key('pki_ds_password') or\
                not len(sensitive['pki_ds_password']):
                 config.pki_log.error(
-                    log.PKIHELPER_UNDEFINED_DS_PASSWORD_1,
-                    config.pkideployment_cfg,
+                    log.PKIHELPER_UNDEFINED_CONFIGURATION_FILE_ENTRY_2,
+                    "pki_ds_password",
+                    master['pki_deployment_cfg'],
                     extra=config.PKI_INDENTATION_LEVEL_2)
                 sys.exit(1)
             # Verify existence of Admin Password (except for Clones)
@@ -430,8 +431,9 @@ class configuration_file:
                 if not sensitive.has_key('pki_admin_password') or\
                    not len(sensitive['pki_admin_password']):
                     config.pki_log.error(
-                        log.PKIHELPER_UNDEFINED_ADMIN_PASSWORD_1,
-                        config.pkideployment_cfg,
+                        log.PKIHELPER_UNDEFINED_CONFIGURATION_FILE_ENTRY_2,
+                        "pki_admin_password",
+                        master['pki_deployment_cfg'],
                         extra=config.PKI_INDENTATION_LEVEL_2)
                     sys.exit(1)
             # If required, verify existence of Backup Password
@@ -439,16 +441,27 @@ class configuration_file:
                 if not sensitive.has_key('pki_backup_password') or\
                    not len(sensitive['pki_backup_password']):
                     config.pki_log.error(
-                        log.PKIHELPER_UNDEFINED_BACKUP_PASSWORD_1,
-                        config.pkideployment_cfg,
+                        log.PKIHELPER_UNDEFINED_CONFIGURATION_FILE_ENTRY_2,
+                        "pki_backup_password",
+                        master['pki_deployment_cfg'],
                         extra=config.PKI_INDENTATION_LEVEL_2)
                     sys.exit(1)
+            # Verify existence of Client Pin for NSS client security databases
+            if not sensitive.has_key('pki_client_database_password') or\
+               not len(sensitive['pki_client_database_password']):
+                config.pki_log.error(
+                    log.PKIHELPER_UNDEFINED_CLIENT_DATABASE_PASSWORD_2,
+                    "pki_client_database_password",
+                    master['pki_deployment_cfg'],
+                    extra=config.PKI_INDENTATION_LEVEL_2)
+                sys.exit(1)
             # Verify existence of Client PKCS #12 Password for Admin Cert
             if not sensitive.has_key('pki_client_pkcs12_password') or\
                not len(sensitive['pki_client_pkcs12_password']):
                 config.pki_log.error(
-                    log.PKIHELPER_UNDEFINED_CLIENT_PKCS12_PASSWORD_1,
-                    config.pkideployment_cfg,
+                    log.PKIHELPER_UNDEFINED_CONFIGURATION_FILE_ENTRY_2,
+                    "pki_client_pkcs12_password",
+                    master['pki_deployment_cfg'],
                     extra=config.PKI_INDENTATION_LEVEL_2)
                 sys.exit(1)
             # Verify existence of PKCS #12 Password (ONLY for Clones)
@@ -456,8 +469,9 @@ class configuration_file:
                 if not sensitive.has_key('pki_clone_pkcs12_password') or\
                    not len(sensitive['pki_clone_pkcs12_password']):
                     config.pki_log.error(
-                        log.PKIHELPER_UNDEFINED_CLONE_PKCS12_PASSWORD_1,
-                        config.pkideployment_cfg,
+                        log.PKIHELPER_UNDEFINED_CONFIGURATION_FILE_ENTRY_2,
+                        "pki_clone_pkcs12_password",
+                        master['pki_deployment_cfg'],
                         extra=config.PKI_INDENTATION_LEVEL_2)
                     sys.exit(1)
             # Verify existence of Security Domain Password File
@@ -468,8 +482,20 @@ class configuration_file:
                 if not sensitive.has_key('pki_security_domain_password') or\
                    not len(sensitive['pki_security_domain_password']):
                     config.pki_log.error(
-                        log.PKIHELPER_UNDEFINED_SECURITY_DOMAIN_PASSWORD_1,
-                        config.pkideployment_cfg,
+                        log.PKIHELPER_UNDEFINED_CONFIGURATION_FILE_ENTRY_2,
+                        "pki_security_domain_password",
+                        master['pki_deployment_cfg'],
+                        extra=config.PKI_INDENTATION_LEVEL_2)
+                    sys.exit(1)
+            # If required, verify existence of Token Password
+            if not len(master['pki_token_name']) or\
+               not master['pki_token_name'] == "internal":
+                if not sensitive.has_key('pki_token_password') or\
+                   not len(sensitive['pki_token_password']):
+                    config.pki_log.error(
+                        log.PKIHELPER_UNDEFINED_CONFIGURATION_FILE_ENTRY_2,
+                        "pki_token_password",
+                        master['pki_deployment_cfg'],
                         extra=config.PKI_INDENTATION_LEVEL_2)
                     sys.exit(1)
         return
@@ -483,30 +509,97 @@ class configuration_file:
                    config.str2bool(master['pki_subordinate']):
                     config.pki_log.error(
                         log.PKIHELPER_MUTUALLY_EXCLUSIVE_CLONE_EXTERNAL_SUB_CA,
-                        config.pkideployment_cfg,
+                        master['pki_deployment_cfg'],
                         extra=config.PKI_INDENTATION_LEVEL_2)
                     sys.exit(1)
                 elif config.str2bool(master['pki_clone']) and\
                      config.str2bool(master['pki_external']):
                     config.pki_log.error(
                         log.PKIHELPER_MUTUALLY_EXCLUSIVE_CLONE_EXTERNAL_CA,
-                        config.pkideployment_cfg,
+                        master['pki_deployment_cfg'],
                         extra=config.PKI_INDENTATION_LEVEL_2)
                     sys.exit(1)
                 elif config.str2bool(master['pki_clone']) and\
                      config.str2bool(master['pki_subordinate']):
                     config.pki_log.error(
                         log.PKIHELPER_MUTUALLY_EXCLUSIVE_CLONE_SUB_CA,
-                        config.pkideployment_cfg,
+                        master['pki_deployment_cfg'],
                         extra=config.PKI_INDENTATION_LEVEL_2)
                     sys.exit(1)
                 elif config.str2bool(master['pki_external']) and\
                      config.str2bool(master['pki_subordinate']):
                     config.pki_log.error(
                         log.PKIHELPER_MUTUALLY_EXCLUSIVE_EXTERNAL_SUB_CA,
-                        config.pkideployment_cfg,
+                        master['pki_deployment_cfg'],
+                        extra=config.PKI_INDENTATION_LEVEL_2)
+                    sys.exit(1)
+
+    def verify_predefined_configuration_file_data(self):
+        # Silently verify the existence of any required 'predefined' data
+        if master['pki_subsystem'] in config.PKI_TOMCAT_SUBSYSTEMS:
+            if config.str2bool(config.pki_master_dict['pki_clone']):
+                # Verify existence of clone parameters
+                if not master.has_key('pki_clone_pkcs12_path') or\
+                   not len(master['pki_clone_pkcs12_path']):
+                    config.pki_log.error(
+                        log.PKIHELPER_UNDEFINED_CONFIGURATION_FILE_ENTRY_2,
+                        "pki_clone_pkcs12_path",
+                        master['pki_deployment_cfg'],
                         extra=config.PKI_INDENTATION_LEVEL_2)
                     sys.exit(1)
+                if not master.has_key('pki_clone_replication_security') or\
+                   not len(master['pki_clone_replication_security']):
+                    config.pki_log.error(
+                        log.PKIHELPER_UNDEFINED_CONFIGURATION_FILE_ENTRY_2,
+                        "pki_clone_replication_security",
+                        master['pki_deployment_cfg'],
+                        extra=config.PKI_INDENTATION_LEVEL_2)
+                    sys.exit(1)
+                if not master.has_key('pki_clone_uri') or\
+                   not len(master['pki_clone_uri']):
+                    config.pki_log.error(
+                        log.PKIHELPER_UNDEFINED_CONFIGURATION_FILE_ENTRY_2,
+                        "pki_clone_uri",
+                        master['pki_deployment_cfg'],
+                        extra=config.PKI_INDENTATION_LEVEL_2)
+                    sys.exit(1)
+            elif master['pki_subsystem'] == "CA" and\
+                 config.str2bool(config.pki_master_dict['pki_external']):
+                if not master.has_key('pki_external_step_two') or\
+                   not len(master['pki_external_step_two']):
+                    config.pki_log.error(
+                        log.PKIHELPER_UNDEFINED_CONFIGURATION_FILE_ENTRY_2,
+                        "pki_external_step_two",
+                        master['pki_deployment_cfg'],
+                        extra=config.PKI_INDENTATION_LEVEL_2)
+                    sys.exit(1)
+                if not config.str2bool(config.pki_master_dict['pki_step_two']):
+                    if not master.has_key('pki_external_csr_path') or\
+                       not len(master['pki_external_csr_path']):
+                        config.pki_log.error(
+                            log.PKIHELPER_UNDEFINED_CONFIGURATION_FILE_ENTRY_2,
+                            "pki_external_csr_path",
+                            master['pki_deployment_cfg'],
+                            extra=config.PKI_INDENTATION_LEVEL_2)
+                        sys.exit(1)
+                else:
+                    if not master.has_key('pki_external_ca_cert_chain_path') or\
+                       not len(master['pki_external_ca_cert_chain_path']):
+                        config.pki_log.error(
+                            log.PKIHELPER_UNDEFINED_CONFIGURATION_FILE_ENTRY_2,
+                            "pki_external_ca_cert_chain_path",
+                            master['pki_deployment_cfg'],
+                            extra=config.PKI_INDENTATION_LEVEL_2)
+                        sys.exit(1)
+                    if not master.has_key('pki_external_ca_cert_path') or\
+                       not len(master['pki_external_ca_cert_path']):
+                        config.pki_log.error(
+                            log.PKIHELPER_UNDEFINED_CONFIGURATION_FILE_ENTRY_2,
+                            "pki_external_ca_cert_path",
+                            master['pki_deployment_cfg'],
+                            extra=config.PKI_INDENTATION_LEVEL_2)
+                        sys.exit(1)
+        return
 
     def populate_non_default_ports(self):
         if master['pki_http_port'] != \
@@ -557,6 +650,20 @@ class configuration_file:
                 sys.exit(1)
         return
 
+    def verify_command_matches_configuration_file(self):
+        # Silently verify that the command-line parameters match the values
+        # that are present in the corresponding configuration file
+        if master['pki_deployment_executable'] == 'pkidestroy':
+            if master['pki_deployed_instance_name'] !=\
+               master['pki_instance_id']:
+                config.pki_log.error(
+                    log.PKIHELPER_COMMAND_LINE_PARAMETER_MISMATCH_2,
+                    master['pki_deployed_instance_name'],
+                    master['pki_instance_id'],
+                    extra=config.PKI_INDENTATION_LEVEL_2)
+                sys.exit(1)
+        return
+
 
 
 # PKI Deployment XML File Class
@@ -677,6 +784,32 @@ class instance:
             sys.exit(1)
         return rv
 
+    def verify_subsystem_exists(self):
+        try:
+            if not os.path.exists(master['pki_subsystem_path']):
+                config.pki_log.error(log.PKI_SUBSYSTEM_DOES_NOT_EXIST_2,
+                                     master['pki_subsystem'],
+                                     master['pki_instance_id'],
+                                     extra=config.PKI_INDENTATION_LEVEL_2)
+                sys.exit(1)
+        except OSError as exc:
+            config.pki_log.error(log.PKI_OSERROR_1, exc,
+                                 extra=config.PKI_INDENTATION_LEVEL_2)
+            sys.exit(1)
+
+    def verify_subsystem_does_not_exist(self):
+        try:
+            if os.path.exists(master['pki_subsystem_path']):
+                config.pki_log.error(log.PKI_SUBSYSTEM_ALREADY_EXISTS_2,
+                                     master['pki_subsystem'],
+                                     master['pki_instance_id'],
+                                     extra=config.PKI_INDENTATION_LEVEL_2)
+                sys.exit(1)
+        except OSError as exc:
+            config.pki_log.error(log.PKI_OSERROR_1, exc,
+                                 extra=config.PKI_INDENTATION_LEVEL_2)
+            sys.exit(1)
+
 
 # PKI Deployment Directory Class
 class directory:
@@ -816,6 +949,17 @@ class directory:
                 sys.exit(1)
         return
 
+    def exists(self, name):
+        try:
+            if not os.path.exists(name) or not os.path.isdir(name):
+                return False
+            else:
+                return True
+        except OSError as exc:
+            config.pki_log.error(log.PKI_OSERROR_1, exc,
+                                 extra=config.PKI_INDENTATION_LEVEL_2)
+            sys.exit(1)
+
     def is_empty(self, name):
         try:
             if not os.listdir(name):
@@ -1182,6 +1326,17 @@ class file:
                 sys.exit(1)
         return
 
+    def exists(self, name):
+        try:
+            if not os.path.exists(name) or not os.path.isfile(name):
+                return False
+            else:
+                return True
+        except OSError as exc:
+            config.pki_log.error(log.PKI_OSERROR_1, exc,
+                                 extra=config.PKI_INDENTATION_LEVEL_2)
+            sys.exit(1)
+
     def copy(self, old_name, new_name, uid=None, gid=None,
              perms=config.PKI_DEPLOYMENT_DEFAULT_FILE_PERMISSIONS, acls=None,
              overwrite_flag=False, critical_failure=True):
@@ -1618,6 +1773,17 @@ class symlink:
                 sys.exit(1)
         return
 
+    def exists(self, name):
+        try:
+            if not os.path.exists(name) or not os.path.islink(name):
+                return False
+            else:
+                return True
+        except OSError as exc:
+            config.pki_log.error(log.PKI_OSERROR_1, exc,
+                                 extra=config.PKI_INDENTATION_LEVEL_2)
+            sys.exit(1)
+
 
 # PKI Deployment War File Class
 class war:
@@ -2149,6 +2315,7 @@ class jython:
             property = ""
             # Compose this "jython" command
             data = pickle.dumps(master)
+            sensitive_data = pickle.dumps(sensitive)
             ld_library_path = "LD_LIBRARY_PATH"
             if master['pki_architecture'] == 64:
                 ld_library_path = ld_library_path + "=" +\
@@ -2158,7 +2325,8 @@ class jython:
                 ld_library_path = ld_library_path + "=" +\
                                   "/usr/lib/jss:/usr/lib:/lib"
             command = "export" + " " + ld_library_path + ";" + "jython" + " " +\
-                      property + " " + scriptlet + " " + "\"" + data + "\""
+                      property + " " + scriptlet + " " + "\"" + data + "\"" +\
+                      " " + "\"" + sensitive_data + "\""
             # Display this "jython" command
             config.pki_log.info(
                 log.PKIHELPER_INVOKE_JYTHON_3,
diff --git a/base/deploy/src/scriptlets/pkijython.py b/base/deploy/src/scriptlets/pkijython.py
index cb1c1d9..deb4c4d 100644
--- a/base/deploy/src/scriptlets/pkijython.py
+++ b/base/deploy/src/scriptlets/pkijython.py
@@ -154,23 +154,6 @@ import pkimessages as log
 
 
 # PKI Deployment Jython Helper Functions
-def extract_sensitive_data(configuration_file):
-    "Read 'sensitive' configuration file section into a dictionary"
-    try:
-        parser = ConfigParser.ConfigParser()
-        # Make keys case-sensitive!
-        parser.optionxform = str
-        parser.read(configuration_file)
-        # return dict(parser._sections['Sensitive'])
-        dictionary = {}
-        for option in parser.options('Sensitive'):
-            dictionary[option] = parser.get('Sensitive', option)
-        return dictionary
-    except ConfigParser.ParsingError, err:
-        javasystem.out.println(log.PKI_JYTHON_EXCEPTION_PARSER + " '" +\
-                               configuration_file + "':  " + str(err))
-        javasystem.exit(1)
-
 def generateCRMFRequest(token, keysize, subjectdn, dualkey):
         kg = token.getKeyPairGenerator(KeyPairAlgorithm.RSA)
         x = Integer(keysize)
@@ -285,7 +268,7 @@ class rest_client:
             e.printStackTrace()
             javasystem.exit(1)
 
-    def construct_pki_configuration_data(self, master, token):
+    def construct_pki_configuration_data(self, master, sensitive, token):
         data = None
         if master['pki_jython_log_level'] >= config.PKI_JYTHON_INFO_LOG_LEVEL:
             print "%s %s '%s'" %\
@@ -293,10 +276,9 @@ class rest_client:
                    log.PKI_JYTHON_CONSTRUCTING_PKI_DATA,
                    master['pki_subsystem'])
         if not master['pki_dry_run_flag']:
-            sensitive = extract_sensitive_data(master['pki_deployment_cfg'])
             data = ConfigurationData()
             # Miscellaneous Configuration Information
-            data.setPin(master['pki_one_time_pin'])
+            data.setPin(sensitive['pki_one_time_pin'])
             data.setToken(ConfigurationData.TOKEN_DEFAULT)
             if master['pki_instance_type'] == "Tomcat":
                 data.setSubsystemName(master['pki_subsystem_name'])
@@ -569,7 +551,7 @@ class rest_client:
             data.setSystemCerts(systemCerts)
         return data
 
-    def configure_pki_data(self, data, master):
+    def configure_pki_data(self, data, master, sensitive):
         if master['pki_jython_log_level'] >= config.PKI_JYTHON_INFO_LOG_LEVEL:
             print "%s %s '%s'" %\
                   (log.PKI_JYTHON_INDENTATION_2,
@@ -577,7 +559,6 @@ class rest_client:
                    master['pki_subsystem'])
         if not master['pki_dry_run_flag']:
             try:
-                sensitive = extract_sensitive_data(master['pki_deployment_cfg'])
                 response = self.client.configure(data)
                 javasystem.out.println(log.PKI_JYTHON_RESPONSE_STATUS +\
                                        " " + response.getStatus())
diff --git a/base/deploy/src/scriptlets/pkimanifest.py b/base/deploy/src/scriptlets/pkimanifest.py
index 4f45e4b..04a638f 100644
--- a/base/deploy/src/scriptlets/pkimanifest.py
+++ b/base/deploy/src/scriptlets/pkimanifest.py
@@ -65,8 +65,6 @@ class record(object):
 
 # PKI Deployment Manifest File Class
 class file:
-    """FUTURE:  Consider creating a single manifest file
-       that is always overwritten."""
     global database
     filename = None
 
diff --git a/base/deploy/src/scriptlets/pkimessages.py b/base/deploy/src/scriptlets/pkimessages.py
index 9dfd454..ccd7570 100644
--- a/base/deploy/src/scriptlets/pkimessages.py
+++ b/base/deploy/src/scriptlets/pkimessages.py
@@ -55,17 +55,6 @@ PKI_VERBOSITY=\
 
 # PKI Deployment Error Messages
 PKI_BADZIPFILE_ERROR_1 = "zipfile.BadZipFile:  %s!"
-PKI_CUSTOM_APACHE_INSTANCE_1 = "When a custom '%s' subsystem is being "\
-                               "deployed, the 'instance', 'http_port', and "\
-                               "'https_port' must ALL be specified!"
-PKI_CUSTOM_TOMCAT_INSTANCE_1 = "When a custom '%s' subsystem is being "\
-                               "deployed, the 'instance', 'http_port', "\
-                               "'https_port', and 'ajp_port' must ALL be "\
-                               "specified!"
-PKI_CUSTOM_TOMCAT_AJP_PORT_1 = "When a custom '%s' subsystem is being "\
-                               "deployed, ONLY the 'instance', "\
-                               "'http_port', and 'https_port' MUST be "\
-                               "specified; NO 'ajp_port' should be requested!"
 PKI_DIRECTORY_ALREADY_EXISTS_1 = "Directory '%s' already exists!"
 PKI_DIRECTORY_ALREADY_EXISTS_NOT_A_DIRECTORY_1 = "Directory '%s' already "\
                                                  "exists BUT it is NOT a "\
@@ -81,6 +70,7 @@ PKI_FILE_ALREADY_EXISTS_NOT_A_FILE_1 = "File '%s' already "\
 PKI_FILE_MISSING_OR_NOT_A_FILE_1 = "File '%s' is either missing "\
                                    "or is NOT a regular file!"
 PKI_FILE_NOT_A_WAR_FILE_1 = "File '%s' is NOT a war file!"
+PKI_INSTANCE_DOES_NOT_EXIST_1 = "PKI instance '%s' does NOT exist!"
 PKI_SECURITY_DATABASES_ALREADY_EXIST_3 = "Security databases '%s', '%s', "\
                                          "and/or '%s' already exist!"
 PKI_SECURITY_DATABASES_DO_NOT_EXIST_3 = "Security databases '%s', '%s', "\
@@ -113,6 +103,17 @@ PKIDESTROY_BEGIN_MESSAGE_2 = "BEGIN destroying subsystem '%s' of "\
                              "instance '%s' . . ."
 PKIDESTROY_END_MESSAGE_2 = "END destroying subsystem '%s' of "\
                            "instance '%s'"
+PKIDESTROY_EPILOG =\
+"REMINDER:\n\n"\
+"    The default PKI instance path will be calculated and placed in front\n"\
+"    of the mandatory '-i <instance>' parameter, and the values that reside\n"\
+"    in a copy of the 'pkideployment.cfg' file that was most recently used\n"\
+"    by this instance's 'pkispawn' (or 'pkispawn -u') command will be\n"\
+"    utilized by 'pkidestroy' to remove this instance.\n\n"\
+"    Finally, if an optional '-p <prefix>' is defined, this value WILL be\n"\
+"    prepended to the default PKI instance path which is placed in front\n"\
+"    of the specified '-i <instance>' parameter.\n\n" +\
+PKI_VERBOSITY
 PKIRESPAWN_BEGIN_MESSAGE_2 = "BEGIN respawning subsystem '%s' of "\
                              "instance '%s' . . ."
 PKIRESPAWN_END_MESSAGE_2 = "END respawning subsystem '%s' of "\
@@ -121,6 +122,20 @@ PKISPAWN_BEGIN_MESSAGE_2 = "BEGIN spawning subsystem '%s' of "\
                            "instance '%s' . . ."
 PKISPAWN_END_MESSAGE_2 = "END spawning subsystem '%s' of "\
                          "instance '%s'"
+PKISPAWN_EPILOG =\
+"REMINDER:\n\n"\
+"    If two or more Apache or Tomcat PKI 'instances' are specified via\n"\
+"    separate configuration files, remember that the following parameters\n"\
+"    MUST differ between PKI 'instances':\n\n"\
+"        Apache:  'pki_instance_name', 'pki_http_port', and 'pki_https_port'\n"\
+"        Tomcat:  'pki_instance_name', 'pki_http_port', 'pki_https_port',\n"\
+"                 'pki_ajp_port', and 'pki_tomcat_server_port'\n\n"\
+"    Optionally, the 'pki_admin_domain_name' may be changed instead of, or\n"\
+"    in addition to, the 'pki_instance_name' since a PKI instance is\n"\
+"    defined as '${pki_instance_name}[.${pki_admin_domain_name}]'.\n\n"\
+"    Finally, if an optional '-p <prefix>' is defined, this value WILL NOT\n"\
+"    be prepended in front of the mandatory '-f <configuration_file>'.\n\n" +\
+PKI_VERBOSITY
 
 
 # PKI Deployment "Helper" Messages
@@ -147,6 +162,9 @@ PKIHELPER_CERTUTIL_SELF_SIGNED_CERTIFICATE_1 = "executing '%s'"
 PKIHELPER_CHMOD_2 = "chmod %o %s"
 PKIHELPER_CHOWN_3 = "chown %s:%s %s"
 PKIHELPER_CHOWN_H_3 = "chown -h %s:%s %s"
+PKIHELPER_COMMAND_LINE_PARAMETER_MISMATCH_2 = "the command-line parameter "\
+                                              "'%s' DOES NOT match the "\
+                                              "configuration file value '%s'!"
 PKIHELPER_COPY_WITH_SLOT_SUBSTITUTION_2 = "copying '%s' --> '%s' "\
                                           "with slot substitution"
 PKIHELPER_CP_P_2 = "cp -p %s %s"
@@ -166,7 +184,7 @@ PKIHELPER_GROUP_ADD_KEYERROR_1 = "KeyError:  pki_group %s"
 PKIHELPER_INVALID_SELINUX_CONTEXT_FOR_PORT = "port %s has invalid selinux "\
                                              "context %s"
 PKIHELPER_INVOKE_JYTHON_3 = "executing 'export %s;"\
-                            "jython %s %s <master_dictionary>'"
+                            "jython %s %s <master_dictionary> <sensitive_data>'"
 PKIHELPER_IS_A_DIRECTORY_1 = "'%s' is a directory"
 PKIHELPER_IS_A_FILE_1 = "'%s' is a file"
 PKIHELPER_IS_A_SYMLINK_1 = "'%s' is a symlink"
@@ -209,18 +227,11 @@ PKIHELPER_TOMCAT_INSTANCES_2 = "instance '%s' contains '%d' "\
                                "Tomcat PKI subsystems"
 PKIHELPER_TOUCH_1 = "touch %s"
 PKIHELPER_UID_2 = "UID of '%s' is %s"
-PKIHELPER_UNDEFINED_ADMIN_PASSWORD_1 =\
-    "A value for 'pki_admin_password' MUST be defined in '%s'"
-PKIHELPER_UNDEFINED_BACKUP_PASSWORD_1 =\
-    "A value for 'pki_backup_password' MUST be defined in '%s'"
-PKIHELPER_UNDEFINED_CLIENT_PKCS12_PASSWORD_1 =\
-    "A value for 'pki_client_pkcs12_password' MUST be defined in '%s'"
-PKIHELPER_UNDEFINED_CLONE_PKCS12_PASSWORD_1 =\
-    "A value for 'pki_clone_pkcs12_password' MUST be defined in '%s'"
-PKIHELPER_UNDEFINED_DS_PASSWORD_1 =\
-    "A value for 'pki_ds_password' MUST be defined in '%s'"
-PKIHELPER_UNDEFINED_SECURITY_DOMAIN_PASSWORD_1 =\
-    "A value for 'pki_security_domain_password' MUST be defined in '%s'"
+PKIHELPER_UNDEFINED_CLIENT_DATABASE_PASSWORD_2 =\
+    "Either a value for '%s' MUST be defined in '%s', or "\
+    "the randomly generated client pin MUST be used"
+PKIHELPER_UNDEFINED_CONFIGURATION_FILE_ENTRY_2 =\
+    "A value for '%s' MUST be defined in '%s'"
 PKIHELPER_USER_1 = "retrieving UID for '%s' . . ."
 PKIHELPER_USER_ADD_2 = "adding UID '%s' for user '%s' . . ."
 PKIHELPER_USER_ADD_DEFAULT_2 = "adding default UID '%s' for user '%s' . . ."
diff --git a/base/deploy/src/scriptlets/pkiparser.py b/base/deploy/src/scriptlets/pkiparser.py
index 7f27d89..cd703c7 100644
--- a/base/deploy/src/scriptlets/pkiparser.py
+++ b/base/deploy/src/scriptlets/pkiparser.py
@@ -24,6 +24,8 @@ import ConfigParser
 import argparse
 import logging
 import os
+import random
+import string
 import sys
 import time
 
@@ -36,16 +38,20 @@ import pkimessages as log
 # PKI Deployment Helper Functions
 def process_command_line_arguments(argv):
     "Read and process command-line options"
+    config.pki_deployment_executable = os.path.basename(argv[0])
     description = None
-    if os.path.basename(argv[0]) == 'pkispawn':
+    if config.pki_deployment_executable == 'pkispawn':
         description = 'PKI Instance Installation and Configuration'
-    elif os.path.basename(argv[0]) == 'pkidestroy':
+        epilog = log.PKISPAWN_EPILOG
+    elif config.pki_deployment_executable == 'pkidestroy':
         description = 'PKI Instance Removal'
+        epilog = log.PKIDESTROY_EPILOG
     parser = argparse.ArgumentParser(
                  description=description,
                  add_help=False,
                  formatter_class=argparse.RawDescriptionHelpFormatter,
-                 epilog=log.PKI_VERBOSITY)
+                 epilog=epilog)
+    # Establish 'Mandatory' command-line options
     mandatory = parser.add_argument_group('mandatory arguments')
     mandatory.add_argument('-s',
                            dest='pki_subsystem', action='store',
@@ -53,12 +59,20 @@ def process_command_line_arguments(argv):
                            required=True, metavar='<subsystem>',
                            help='where <subsystem> is '
                                 'CA, KRA, OCSP, RA, TKS, or TPS')
-    if os.path.basename(argv[0]) == 'pkispawn':
+    if config.pki_deployment_executable == 'pkispawn':
         mandatory.add_argument('-f',
                                dest='pkideployment_cfg', action='store',
                                nargs=1, required=True, metavar='<file>',
-                               help='specifies configuration filename')
-
+                               help='configuration filename '
+                                    '(MUST specify complete path)')
+    elif config.pki_deployment_executable == 'pkidestroy':
+        mandatory.add_argument('-i',
+                               dest='pki_deployed_instance_name',
+                               action='store',
+                               nargs=1, metavar='<instance>',
+                               help='FORMAT:  ${pki_instance_name}'
+                                    '[.${pki_admin_domain_name}]')
+    # Establish 'Optional' command-line options
     optional = parser.add_argument_group('optional arguments')
     optional.add_argument('--dry_run',
                           dest='pki_dry_run_flag', action='store_true',
@@ -66,73 +80,40 @@ def process_command_line_arguments(argv):
     optional.add_argument('-h', '--help',
                           dest='help', action='help',
                           help='show this help message and exit')
-    if os.path.basename(argv[0]) == 'pkispawn':
+    if config.pki_deployment_executable == 'pkispawn':
         optional.add_argument('-u',
                               dest='pki_update_flag', action='store_true',
                               help='update instance of specified subsystem')
     optional.add_argument('-v',
                           dest='pki_verbosity', action='count',
                           help='display verbose information (details below)')
-    custom = parser.add_argument_group('custom arguments '
-                                       '(OVERRIDES configuration file values)')
-    if os.path.basename(argv[0]) == 'pkispawn':
-        custom.add_argument('-i',
-                            dest='custom_pki_instance_name', action='store',
-                            nargs=1, metavar='<instance>',
-                            help='PKI instance name '
-                                 '(MUST specify REQUIRED ports)')
-        custom.add_argument('-d',
-                            dest='custom_pki_admin_domain_name', action='store',
-                            nargs=1, metavar='<admin_domain>',
-                            help='PKI admin domain name (instance name suffix)')
-        custom.add_argument('--http_port',
-                            dest='custom_pki_http_port', action='store',
-                            nargs=1, metavar='<port>',
-                            help='HTTP port (CA, KRA, OCSP, RA, TKS, TPS)')
-        custom.add_argument('--https_port',
-                            dest='custom_pki_https_port', action='store',
-                            nargs=1, metavar='<port>',
-                            help='HTTPS port (CA, KRA, OCSP, RA, TKS, TPS)')
-        custom.add_argument('--ajp_port',
-                            dest='custom_pki_ajp_port', action='store',
-                            nargs=1, metavar='<port>',
-                            help='AJP port (CA, KRA, OCSP, TKS)')
-    elif os.path.basename(argv[0]) == 'pkidestroy':
-        custom.add_argument('-i',
-                            dest='custom_pki_instance_name', action='store',
-                            nargs=1, metavar='<instance>',
-                            help='PKI instance name')
-        custom.add_argument('-d',
-                            dest='custom_pki_admin_domain_name', action='store',
-                            nargs=1, metavar='<admin_domain>',
-                            help='PKI admin domain name (instance name suffix)')
-
+    # Establish 'Test' command-line options
     test = parser.add_argument_group('test arguments')
     test.add_argument('-p',
                       dest='pki_root_prefix', action='store',
                       nargs=1, metavar='<prefix>',
                       help='directory prefix to specify local directory '
                            '[TEST ONLY]')
+    # Parse command-line options
     args = parser.parse_args()
-
+    # Process 'Mandatory' command-line options
+    #    '-s'
     config.pki_subsystem = str(args.pki_subsystem).strip('[\']')
+    if config.pki_deployment_executable == 'pkispawn':
+        #    '-f'
+        config.pkideployment_cfg = str(args.pkideployment_cfg).strip('[\']')
+    elif config.pki_deployment_executable == 'pkidestroy':
+        #    '-i'
+        config.pki_deployed_instance_name =\
+            str(args.pki_deployed_instance_name).strip('[\']')
+    # Process 'Optional' command-line options
+    #    '--dry_run'
     if args.pki_dry_run_flag:
         config.pki_dry_run_flag = args.pki_dry_run_flag
-    if not args.pki_root_prefix is None:
-        config.pki_root_prefix = str(args.pki_root_prefix).strip('[\']')
-    if config.pki_root_prefix is None or\
-       len(config.pki_root_prefix) == 0:
-        config.pki_root_prefix = ""
-    elif not os.path.exists(config.pki_root_prefix) or\
-         not os.path.isdir(config.pki_root_prefix):
-        print "ERROR:  " +\
-              log.PKI_DIRECTORY_MISSING_OR_NOT_A_DIRECTORY_1 %\
-              config.pki_root_prefix
-        print
-        parser.print_help()
-        parser.exit(-1);
-    if os.path.basename(argv[0]) == 'pkispawn':
+    if config.pki_deployment_executable == 'pkispawn':
+        #    '-u'
         config.pki_update_flag = args.pki_update_flag
+    #    '-v'
     if args.pki_verbosity == 1:
         config.pki_jython_log_level = config.PKI_JYTHON_INFO_LOG_LEVEL
         config.pki_console_log_level = logging.INFO
@@ -155,151 +136,47 @@ def process_command_line_arguments(argv):
         config.pki_jython_log_level = config.PKI_JYTHON_WARNING_LOG_LEVEL
         config.pki_console_log_level = logging.WARNING
         config.pki_log_level = logging.INFO
-    if not args.custom_pki_instance_name is None:
-        config.custom_pki_instance_name =\
-            str(args.custom_pki_instance_name).strip('[\']')
-    if not args.custom_pki_admin_domain_name is None:
-        config.custom_pki_admin_domain_name =\
-            str(args.custom_pki_admin_domain_name).strip('[\']')
-    if config.pki_subsystem in config.PKI_APACHE_SUBSYSTEMS:
-        if not config.custom_pki_instance_name is None:
-            default_pki_instance_name = config.custom_pki_instance_name
-        else:
-            default_pki_instance_name =\
-                config.PKI_DEPLOYMENT_DEFAULT_APACHE_INSTANCE_NAME
-        if not config.custom_pki_admin_domain_name is None:
-            default_pki_instance_path =\
-                config.pki_root_prefix +\
-                config.PKI_DEPLOYMENT_BASE_ROOT + "/" +\
-                default_pki_instance_name + "." +\
-                config.custom_pki_admin_domain_name + "/" +\
-                config.pki_subsystem.lower()
-        else:
-            default_pki_instance_path =\
-                config.pki_root_prefix +\
-                config.PKI_DEPLOYMENT_BASE_ROOT + "/" +\
-                default_pki_instance_name + "/" +\
-                config.pki_subsystem.lower()
-    elif config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS:
-        if not config.custom_pki_instance_name is None:
-            default_pki_instance_name = config.custom_pki_instance_name
-        else:
-            default_pki_instance_name =\
-                config.PKI_DEPLOYMENT_DEFAULT_TOMCAT_INSTANCE_NAME
-        if not config.custom_pki_admin_domain_name is None:
-            default_pki_instance_path =\
-                config.pki_root_prefix +\
-                config.PKI_DEPLOYMENT_BASE_ROOT + "/" +\
-                default_pki_instance_name + "." +\
-                config.custom_pki_admin_domain_name + "/" +\
-                config.pki_subsystem.lower()
-        else:
-            default_pki_instance_path =\
-                config.pki_root_prefix +\
-                config.PKI_DEPLOYMENT_BASE_ROOT + "/" +\
-                default_pki_instance_name + "/" +\
-                config.pki_subsystem.lower()
-    if os.path.basename(argv[0]) == 'pkispawn':
-        if args.pki_update_flag:
-            # "respawn"
-            if not os.path.exists(default_pki_instance_path):
-                print "ERROR:  " + log.PKI_SUBSYSTEM_DOES_NOT_EXIST_2 %\
-                      (config.pki_subsystem, default_pki_instance_name)
-                print
-                parser.exit(-1);
-        else:
-            # "spawn"
-            if os.path.exists(default_pki_instance_path):
-                print "ERROR:  " + log.PKI_SUBSYSTEM_ALREADY_EXISTS_2 %\
-                      (config.pki_subsystem, default_pki_instance_name)
-                print
-                parser.exit(-1);
-        config.pkideployment_cfg = str(args.pkideployment_cfg).strip('[\']')
-        if not args.custom_pki_http_port is None:
-            config.custom_pki_http_port =\
-                str(args.custom_pki_http_port).strip('[\']')
-        if not args.custom_pki_https_port is None:
-            config.custom_pki_https_port =\
-                str(args.custom_pki_https_port).strip('[\']')
-        if not args.custom_pki_ajp_port is None:
-            if config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS:
-                config.custom_pki_ajp_port =\
-                    str(args.custom_pki_ajp_port).strip('[\']')
-            else:
-                print "ERROR:  " +\
-                      log.PKI_CUSTOM_TOMCAT_AJP_PORT_1 %\
-                      config.pki_subsystem
-                print
-                parser.print_help()
-                parser.exit(-1);
-        if not args.custom_pki_instance_name is None or\
-           not args.custom_pki_http_port is None or\
-           not args.custom_pki_https_port is None or\
-           not args.custom_pki_ajp_port is None:
-            if config.pki_subsystem in config.PKI_APACHE_SUBSYSTEMS:
-                if args.custom_pki_instance_name is None or\
-                   args.custom_pki_http_port is None or\
-                   args.custom_pki_https_port is None:
-                    print "ERROR:  " + log.PKI_CUSTOM_APACHE_INSTANCE_1 %\
-                          config.pki_subsystem
-                    print
-                    parser.print_help()
-                    parser.exit(-1);
-            elif config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS:
-                if args.custom_pki_instance_name is None or\
-                   args.custom_pki_http_port is None or\
-                   args.custom_pki_https_port is None or\
-                   args.custom_pki_ajp_port is None:
-                    print "ERROR:  " + log.PKI_CUSTOM_TOMCAT_INSTANCE_1 %\
-                          config.pki_subsystem
-                    print
-                    parser.print_help()
-                    parser.exit(-1);
-    elif os.path.basename(argv[0]) == 'pkidestroy':
-        # NOTE:  When performing 'pkidestroy', a 'pki_instance_name' and/or
-        #        a 'pki_admin_domain_name' MUST be explicitly specified if
-        #        a PKI instance has NOT been installed in the default location
-        #        using the default PKI instance name!
-        if not os.path.exists(default_pki_instance_path):
+    # Process 'Test' command-line options
+    #    '-p'
+    if not args.pki_root_prefix is None:
+        config.pki_root_prefix = str(args.pki_root_prefix).strip('[\']')
+    # Validate command-line options
+    if config.pki_root_prefix is None or\
+       len(config.pki_root_prefix) == 0:
+        config.pki_root_prefix = ""
+    elif not os.path.exists(config.pki_root_prefix) or\
+         not os.path.isdir(config.pki_root_prefix):
+        print "ERROR:  " +\
+              log.PKI_DIRECTORY_MISSING_OR_NOT_A_DIRECTORY_1 %\
+              config.pki_root_prefix
+        print
+        parser.print_help()
+        parser.exit(-1);
+    if config.pki_deployment_executable == 'pkidestroy':
+        # verify that previously deployed instance exists
+        deployed_pki_instance_path = config.pki_root_prefix +\
+                                     config.PKI_DEPLOYMENT_BASE_ROOT + "/" +\
+                                     config.pki_deployed_instance_name
+        if not os.path.exists(deployed_pki_instance_path):
+            print "ERROR:  " + log.PKI_INSTANCE_DOES_NOT_EXIST_1 %\
+                  deployed_pki_instance_path
+            print
+            parser.exit(-1);
+        # verify that previously deployed subsystem for this instance exists
+        deployed_pki_subsystem_path = deployed_pki_instance_path + "/" +\
+                                      config.pki_subsystem.lower()
+        if not os.path.exists(deployed_pki_subsystem_path):
             print "ERROR:  " + log.PKI_SUBSYSTEM_DOES_NOT_EXIST_2 %\
-                  (config.pki_subsystem, default_pki_instance_name)
+                  (config.pki_subsystem, deployed_pki_instance_path)
             print
             parser.exit(-1);
-        if config.pki_subsystem in config.PKI_APACHE_SUBSYSTEMS:
-            if not config.custom_pki_admin_domain_name is None:
-                default_pki_instance_registry_path =\
-                    config.pki_root_prefix +\
-                    config.PKI_DEPLOYMENT_REGISTRY_ROOT + "/" +\
-                    config.PKI_DEPLOYMENT_DEFAULT_APACHE_SERVICE_NAME + "/" +\
-                    default_pki_instance_name + "." +\
-                    config.custom_pki_admin_domain_name + "/" +\
-                    config.pki_subsystem.lower()
-            else:
-                default_pki_instance_registry_path =\
-                    config.pki_root_prefix +\
-                    config.PKI_DEPLOYMENT_REGISTRY_ROOT + "/" +\
-                    config.PKI_DEPLOYMENT_DEFAULT_APACHE_SERVICE_NAME + "/" +\
-                    default_pki_instance_name + "/" +\
-                    config.pki_subsystem.lower()
-        elif config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS:
-            if not config.custom_pki_admin_domain_name is None:
-                default_pki_instance_registry_path =\
-                    config.pki_root_prefix +\
-                    config.PKI_DEPLOYMENT_REGISTRY_ROOT + "/" +\
-                    config.PKI_DEPLOYMENT_DEFAULT_TOMCAT_SERVICE_NAME + "/" +\
-                    default_pki_instance_name + "." +\
-                    config.custom_pki_admin_domain_name + "/" +\
-                    config.pki_subsystem.lower()
-            else:
-                default_pki_instance_registry_path =\
-                    config.pki_root_prefix +\
-                    config.PKI_DEPLOYMENT_REGISTRY_ROOT + "/" +\
-                    config.PKI_DEPLOYMENT_DEFAULT_TOMCAT_SERVICE_NAME + "/" +\
-                    default_pki_instance_name + "/" +\
-                    config.pki_subsystem.lower()
+        # establish complete path to previously deployed configuration file
         config.pkideployment_cfg =\
-            default_pki_instance_registry_path + "/" +\
+            deployed_pki_subsystem_path + "/" +\
+            "registry" + "/" +\
+            config.pki_subsystem.lower() + "/" +\
             config.PKI_DEPLOYMENT_DEFAULT_CONFIGURATION_FILE
+    # always verify that configuration file exists
     if not os.path.exists(config.pkideployment_cfg) or\
        not os.path.isfile(config.pkideployment_cfg):
         print "ERROR:  " +\
@@ -354,6 +231,8 @@ def compose_pki_master_dictionary():
     try:
         config.pki_master_dict = dict()
         # 'pkispawn'/'pkirespawn'/'pkidestroy' name/value pairs
+        config.pki_master_dict['pki_deployment_executable'] =\
+            config.pki_deployment_executable
         config.pki_master_dict['pki_install_time'] = config.pki_install_time
         config.pki_master_dict['pki_timestamp'] = config.pki_timestamp
         config.pki_master_dict['pki_certificate_timestamp'] =\
@@ -362,13 +241,27 @@ def compose_pki_master_dictionary():
         config.pki_master_dict['pki_hostname'] = config.pki_hostname
         config.pki_master_dict['pki_dns_domainname'] =\
             config.pki_dns_domainname
-        config.pki_master_dict['pki_pin'] = config.pki_pin
-        config.pki_master_dict['pki_client_pin'] = config.pki_client_pin
-        config.pki_master_dict['pki_one_time_pin'] = config.pki_one_time_pin
         config.pki_master_dict['pki_dry_run_flag'] = config.pki_dry_run_flag
         config.pki_master_dict['pki_jython_log_level'] =\
             config.pki_jython_log_level
         config.pki_master_dict['pki_deployment_cfg'] = config.pkideployment_cfg
+        config.pki_master_dict['pki_deployed_instance_name'] =\
+            config.pki_deployed_instance_name
+        # Generate random 'pin's for use as security database passwords
+        # and add these to the "sensitive" key value pairs read in from
+        # the configuration file
+        pin_low  = 100000000000
+        pin_high = 999999999999
+        config.pki_sensitive_dict['pki_pin'] =\
+            random.randint(pin_low, pin_high)
+        config.pki_sensitive_dict['pki_client_pin'] =\
+            random.randint(pin_low, pin_high)
+        # Generate a one-time pin to be used prior to configuration
+        # and add this to the "sensitive" key value pairs read in from
+        # the configuration file
+        config.pki_sensitive_dict['pki_one_time_pin'] =\
+            ''.join(random.choice(string.ascii_letters + string.digits)\
+            for x in range(20))
         # Configuration file name/value pairs
         #     NEVER add "sensitive" key value pairs to the master dictionary!!!
         config.pki_master_dict.update(config.pki_common_dict)
@@ -420,7 +313,7 @@ def compose_pki_master_dictionary():
         #     OLD:  "pki-${pki_subsystem}"
         #           (e. g. Tomcat:  "pki-ca", "pki-kra", "pki-ocsp", "pki-tks")
         #           (e. g. Apache:  "pki-ra", "pki-tps")
-        #     NEW:  "[${pki_admin_domain_name}-]${pki_instance_name}"
+        #     NEW:  "${pki_instance_name}[.${pki_admin_domain_name}]"
         #           (e. g. Tomcat:  "pki-tomcat", "pki-tomcat.example.com")
         #           (e. g. Apache:  "pki-apache", "pki-apache.example.com")
         #
@@ -932,6 +825,9 @@ def compose_pki_master_dictionary():
         config.pki_master_dict['pki_subsystem_log_path'] =\
             os.path.join(config.pki_master_dict['pki_instance_log_path'],
                          config.pki_master_dict['pki_subsystem'].lower())
+        config.pki_master_dict['pki_subsystem_archive_log_path'] =\
+            os.path.join(config.pki_master_dict['pki_subsystem_log_path'],
+                         "archive")
         # Instance-based PKI subsystem configuration name/value pairs
         config.pki_master_dict['pki_subsystem_configuration_path'] =\
             os.path.join(
@@ -983,6 +879,9 @@ def compose_pki_master_dictionary():
         config.pki_master_dict['pki_subsystem_logs_link'] =\
             os.path.join(config.pki_master_dict['pki_subsystem_path'],
                          "logs")
+        config.pki_master_dict['pki_subsystem_registry_link'] =\
+            os.path.join(config.pki_master_dict['pki_subsystem_path'],
+                         "registry")
         # PKI Target (war file) name/value pairs
         if config.pki_master_dict['pki_subsystem'] in\
            config.PKI_TOMCAT_SUBSYSTEMS:
@@ -1232,7 +1131,7 @@ def compose_pki_master_dictionary():
             config.pki_master_dict['PKI_AJP_REDIRECT_PORT_SLOT'] =\
                 config.pki_master_dict['pki_https_port']
             config.pki_master_dict['PKI_CERT_DB_PASSWORD_SLOT'] =\
-                config.pki_master_dict['pki_pin']
+                config.pki_sensitive_dict['pki_pin']
             config.pki_master_dict['PKI_CFG_PATH_NAME_SLOT'] =\
                 config.pki_master_dict['pki_target_cs_cfg']
             config.pki_master_dict['PKI_CLOSE_AJP_PORT_COMMENT_SLOT'] =\
@@ -1285,14 +1184,18 @@ def compose_pki_master_dictionary():
             config.pki_master_dict['PKI_PIDDIR_SLOT'] =\
                 os.path.join("/var/run/pki",
                              "tomcat")
-            config.pki_master_dict['PKI_PROXY_SECURE_PORT_SLOT'] =\
-                config.pki_master_dict['pki_proxy_https_port']
+            if config.str2bool(config.pki_master_dict['pki_enable_proxy']):
+                config.pki_master_dict['PKI_PROXY_SECURE_PORT_SLOT'] =\
+                    config.pki_master_dict['pki_proxy_https_port']
+                config.pki_master_dict['PKI_PROXY_UNSECURE_PORT_SLOT'] =\
+                    config.pki_master_dict['pki_proxy_http_port']
+            else:
+                config.pki_master_dict['PKI_PROXY_SECURE_PORT_SLOT'] = ""
+                config.pki_master_dict['PKI_PROXY_UNSECURE_PORT_SLOT'] = ""
             config.pki_master_dict['PKI_TMPDIR_SLOT'] =\
                 config.pki_master_dict['pki_tomcat_tmpdir_path']
-            config.pki_master_dict['PKI_PROXY_UNSECURE_PORT_SLOT'] =\
-                config.pki_master_dict['pki_proxy_http_port']
             config.pki_master_dict['PKI_RANDOM_NUMBER_SLOT'] =\
-                config.pki_master_dict['pki_one_time_pin']
+                config.pki_sensitive_dict['pki_one_time_pin']
             config.pki_master_dict['PKI_SECURE_PORT_SLOT'] =\
                 config.pki_master_dict['pki_https_port']
             config.pki_master_dict['PKI_SECURE_PORT_CONNECTOR_NAME_SLOT'] =\
@@ -1431,11 +1334,29 @@ def compose_pki_master_dictionary():
         #     deployment configuration file and is NOT redefined below:
         #
         #         config.pki_sensitive_dict['pki_client_pkcs12_password']
+        #         config.pki_master_dict['pki_client_database_purge']
         #
-        config.pki_master_dict['pki_client_path'] =\
-            os.path.join(
-                "/tmp",
-                config.pki_master_dict['pki_instance_id'] + "_" + "client")
+        #     The following variables are established via the specified PKI
+        #     deployment configuration file and potentially overridden below:
+        #
+        #         config.pki_sensitive_dict['pki_client_database_password']
+        #         config.pki_master_dict['pki_client_path']
+        #         config.pki_master_dict['pki_client_pkcs12_path']
+        #
+        if not len(config.pki_sensitive_dict['pki_client_database_password']):
+            # use randomly generated client 'pin'
+            config.pki_sensitive_dict['pki_client_database_password'] =\
+                str(config.pki_sensitive_dict['pki_client_pin'])
+        if not len(config.pki_master_dict['pki_client_path']):
+            config.pki_master_dict['pki_client_path'] =\
+                os.path.join(
+                    "/tmp",
+                    config.pki_master_dict['pki_instance_id'] + "_" + "client")
+        if not len(config.pki_master_dict['pki_client_database_path']):
+            config.pki_master_dict['pki_client_database_path'] =\
+                os.path.join(
+                    config.pki_master_dict['pki_client_path'],
+                    "alias")
         config.pki_master_dict['pki_client_password_conf'] =\
             os.path.join(
                 config.pki_master_dict['pki_client_path'],
@@ -1444,10 +1365,10 @@ def compose_pki_master_dictionary():
             os.path.join(
                 config.pki_master_dict['pki_client_path'],
                 "pkcs12_password.conf")
-        config.pki_master_dict['pki_client_database_path'] =\
-            os.path.join(
-                config.pki_master_dict['pki_client_path'],
-                "alias")
+        if not len(config.pki_master_dict['pki_client_pkcs12_path']):
+            # Store the PKCS #12 file in with the NSS server security databases
+            config.pki_master_dict['pki_client_pkcs12_path'] =\
+                config.pki_master_dict['pki_database_path']
         config.pki_master_dict['pki_client_cert_database'] =\
             os.path.join(config.pki_master_dict['pki_client_database_path'],
                          "cert8.db")
@@ -1461,37 +1382,37 @@ def compose_pki_master_dictionary():
             config.pki_master_dict['pki_client_admin_cert'] = "ca_admin.cert"
             config.pki_master_dict['pki_client_admin_cert_p12'] =\
                 os.path.join(
-                    config.pki_master_dict['pki_client_path'],
+                    config.pki_master_dict['pki_client_pkcs12_path'],
                     "ca_admin_cert.p12")
         elif config.pki_master_dict['pki_subsystem'] == "KRA":
             config.pki_master_dict['pki_client_admin_cert'] = "kra_admin.cert"
             config.pki_master_dict['pki_client_admin_cert_p12'] =\
                 os.path.join(
-                    config.pki_master_dict['pki_client_path'],
+                    config.pki_master_dict['pki_client_pkcs12_path'],
                     "kra_admin_cert.p12")
         elif config.pki_master_dict['pki_subsystem'] == "OCSP":
             config.pki_master_dict['pki_client_admin_cert'] = "ocsp_admin.cert"
             config.pki_master_dict['pki_client_admin_cert_p12'] =\
                 os.path.join(
-                    config.pki_master_dict['pki_client_path'],
+                    config.pki_master_dict['pki_client_pkcs12_path'],
                     "ocsp_admin_cert.p12")
         elif config.pki_master_dict['pki_subsystem'] == "RA":
             config.pki_master_dict['pki_client_admin_cert'] = "ra_admin.cert"
             config.pki_master_dict['pki_client_admin_cert_p12'] =\
                 os.path.join(
-                    config.pki_master_dict['pki_client_path'],
+                    config.pki_master_dict['pki_client_pkcs12_path'],
                     "ra_admin_cert.p12")
         elif config.pki_master_dict['pki_subsystem'] == "TKS":
             config.pki_master_dict['pki_client_admin_cert'] = "tks_admin.cert"
             config.pki_master_dict['pki_client_admin_cert_p12'] =\
                 os.path.join(
-                    config.pki_master_dict['pki_client_path'],
+                    config.pki_master_dict['pki_client_pkcs12_path'],
                     "tks_admin_cert.p12")
         elif config.pki_master_dict['pki_subsystem'] == "TPS":
             config.pki_master_dict['pki_client_admin_cert'] = "tps_admin.cert"
             config.pki_master_dict['pki_client_admin_cert_p12'] =\
                 os.path.join(
-                    config.pki_master_dict['pki_client_path'],
+                    config.pki_master_dict['pki_client_pkcs12_path'],
                     "tps_admin_cert.p12")
         # Jython scriptlet name/value pairs
         config.pki_master_dict['pki_jython_configuration_scriptlet'] =\
@@ -1510,6 +1431,7 @@ def compose_pki_master_dictionary():
         # Jython scriptlet
         # 'Security Domain' Configuration name/value pairs
         # 'Subsystem Name'  Configuration name/value pairs
+        # 'Token'           Configuration name/value pairs
         #
         #     Apache - [RA], [TPS]
         #     Tomcat - [CA], [KRA], [OCSP], [TKS]
@@ -1525,9 +1447,14 @@ def compose_pki_master_dictionary():
         #     The following variables are established via the specified PKI
         #     deployment configuration file and are NOT redefined below:
         #
-        #         config.pki_master_dict['pki_security_domain_https_port']
+        #         config.pki_sensitive_dict['pki_clone_pkcs12_password']
         #         config.pki_sensitive_dict['pki_security_domain_password']
+        #         config.pki_sensitive_dict['pki_token_password']
+        #         config.pki_master_dict['pki_clone_pkcs12_path']
+        #         config.pki_master_dict['pki_clone_uri']
+        #         config.pki_master_dict['pki_security_domain_https_port']
         #         config.pki_master_dict['pki_security_domain_user']
+        #         config.pki_master_dict['pki_token_name']
         #
         #     The following variables are established via the specified PKI
         #     deployment configuration file and potentially overridden below:
@@ -1536,7 +1463,23 @@ def compose_pki_master_dictionary():
         #         config.pki_master_dict['pki_security_domain_name']
         #         config.pki_master_dict['pki_subsystem_name']
         #
-        if config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS:
+        if config.pki_subsystem in config.PKI_APACHE_SUBSYSTEMS:
+            # PKI RA or TPS
+            config.pki_master_dict['pki_security_domain_type'] = "existing"
+            if not len(config.pki_master_dict['pki_security_domain_hostname']):
+                # Guess that it is the local host
+                config.pki_master_dict['pki_security_domain_hostname'] =\
+                    config.pki_master_dict['pki_hostname']
+            config.pki_master_dict['pki_security_domain_uri'] =\
+                "https" + "://" +\
+                config.pki_master_dict['pki_security_domain_hostname'] + ":" +\
+                config.pki_master_dict['pki_security_domain_https_port']
+            if not len(config.pki_master_dict['pki_security_domain_name']):
+                # Guess that security domain is on the local host
+                config.pki_master_dict['pki_security_domain_name'] =\
+                    config.pki_master_dict['pki_dns_domainname'] +\
+                    " " + "Security Domain"
+        elif config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS:
             if config.pki_subsystem == "CA":
                 if config.str2bool(config.pki_master_dict['pki_external']):
                     # External CA
@@ -1591,6 +1534,12 @@ def compose_pki_master_dictionary():
                                 "Subordinate CA" + " " +\
                                 config.pki_master_dict['pki_hostname'] + " " +\
                                 config.pki_master_dict['pki_https_port']
+                        if not len(config.pki_master_dict\
+                                   ['pki_security_domain_name']):
+                            # Guess that security domain is on the local host
+                            config.pki_master_dict['pki_security_domain_name']\
+                                = config.pki_master_dict['pki_dns_domainname']\
+                                + " " + "Security Domain"
             else:
                 # PKI or Cloned KRA, OCSP, or TKS
                 config.pki_master_dict['pki_security_domain_type'] = "existing"
@@ -1604,6 +1553,13 @@ def compose_pki_master_dictionary():
                     config.pki_master_dict['pki_security_domain_hostname'] +\
                     ":" +\
                     config.pki_master_dict['pki_security_domain_https_port']
+                if not config.str2bool(config.pki_master_dict['pki_clone']):
+                    if not len(config.pki_master_dict\
+                               ['pki_security_domain_name']):
+                        # Guess that security domain is on the local host
+                        config.pki_master_dict['pki_security_domain_name'] =\
+                            config.pki_master_dict['pki_dns_domainname'] +\
+                            " " + "Security Domain"
                 if config.pki_subsystem == "KRA":
                     if config.str2bool(config.pki_master_dict['pki_clone']):
                         # Cloned KRA
@@ -1667,10 +1623,11 @@ def compose_pki_master_dictionary():
         #     The following variables are established via the specified PKI
         #     deployment configuration file and are NOT redefined below:
         #
+        #         config.pki_sensitive_dict['pki_ds_password']
+        #         config.pki_master_dict['pki_clone_replication_security']
         #         config.pki_master_dict['pki_ds_bind_dn']
         #         config.pki_master_dict['pki_ds_ldap_port']
         #         config.pki_master_dict['pki_ds_ldaps_port']
-        #         config.pki_sensitive_dict['pki_ds_password']
         #         config.pki_master_dict['pki_ds_remove_data']
         #         config.pki_master_dict['pki_ds_secure_connection']
         #
@@ -1692,6 +1649,20 @@ def compose_pki_master_dictionary():
             config.pki_master_dict['pki_ds_hostname'] =\
                 config.pki_master_dict['pki_hostname']
         # Jython scriptlet
+        # 'External CA' Configuration name/value pairs
+        #
+        #     Tomcat - [External CA]
+        #
+        #     The following variables are established via the specified PKI
+        #     deployment configuration file and are NOT redefined below:
+        #
+        #        config.pki_master_dict['pki_external_ca_cert_chain_path']
+        #        config.pki_master_dict['pki_external_ca_cert_path']
+        #        config.pki_master_dict['pki_external_csr_path']
+        #        config.pki_master_dict['pki_external_step_two']
+        #
+
+        # Jython scriptlet
         # 'Backup' Configuration name/value pairs
         #
         #     Apache - [RA], [TPS]
@@ -1702,8 +1673,8 @@ def compose_pki_master_dictionary():
         #     The following variables are established via the specified PKI
         #     deployment configuration file and are NOT redefined below:
         #
-        #        config.pki_master_dict['pki_backup_keys']
         #        config.pki_sensitive_dict['pki_backup_password']
+        #        config.pki_master_dict['pki_backup_keys']
         #
         #     The following variables are established via the specified PKI
         #     deployment configuration file and potentially overridden below:
@@ -1758,11 +1729,11 @@ def compose_pki_master_dictionary():
         #     The following variables are established via the specified PKI
         #     deployment configuration file and are NOT redefined below:
         #
+        #         config.pki_sensitive_dict['pki_admin_password']
         #         config.pki_master_dict['pki_admin_cert_request_type']
         #         config.pki_master_dict['pki_admin_dualkey']
         #         config.pki_master_dict['pki_admin_keysize']
         #         config.pki_master_dict['pki_admin_name']
-        #         config.pki_sensitive_dict['pki_admin_password']
         #         config.pki_master_dict['pki_admin_uid']
         #
         #     The following variables are established via the specified PKI
@@ -1794,13 +1765,22 @@ def compose_pki_master_dictionary():
             elif config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS:
                 if not config.str2bool(config.pki_master_dict['pki_clone']):
                     if config.pki_master_dict['pki_subsystem'] == "CA":
-                        # PKI CA, Subordinate CA, or External CA
-                        config.pki_master_dict['pki_admin_nickname'] =\
-                            "CA Administrator of Instance" + " " +\
-                            config.pki_master_dict['pki_instance_id'] +\
-                            "&#39;s" + " " +\
-                            config.pki_master_dict['pki_security_domain_name']\
-                            + " " + "ID"
+                        if config.str2bool(
+                            config.pki_master_dict['pki_external']):
+                             # External CA
+                             config.pki_master_dict['pki_admin_nickname'] =\
+                                 "CA Administrator of Instance" + " " +\
+                                 config.pki_master_dict['pki_instance_id'] +\
+                                 "&#39;s" + " " +\
+                                 "External CA ID"
+                        else:
+                            # PKI CA or Subordinate CA
+                            config.pki_master_dict['pki_admin_nickname'] =\
+                                "CA Administrator of Instance" + " " +\
+                                config.pki_master_dict['pki_instance_id'] +\
+                                "&#39;s" + " " +\
+                                config.pki_master_dict\
+                                ['pki_security_domain_name'] + " " + "ID"
                     elif config.pki_master_dict['pki_subsystem'] == "KRA":
                         # PKI KRA
                         config.pki_master_dict['pki_admin_nickname'] =\
@@ -1848,15 +1828,29 @@ def compose_pki_master_dictionary():
             elif config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS:
                 if not config.str2bool(config.pki_master_dict['pki_clone']):
                     if config.pki_master_dict['pki_subsystem'] == "CA":
-                        # PKI CA, Subordinate CA, or External CA
-                        config.pki_master_dict['pki_admin_subject_dn'] =\
-                            "cn=" + "CA Administrator of Instance" + " " +\
-                            config.pki_master_dict['pki_instance_id'] + "," +\
-                            "uid=" + config.pki_master_dict['pki_admin_uid'] +\
-                            "," + "e=" +\
-                            config.pki_master_dict['pki_admin_email'] +\
-                            "," + "o=" +\
-                            config.pki_master_dict['pki_security_domain_name']
+                       if config.str2bool(
+                           config.pki_master_dict['pki_external']):
+                            # External CA
+                            config.pki_master_dict['pki_admin_subject_dn'] =\
+                                "cn=" + "CA Administrator of Instance" + " " +\
+                                config.pki_master_dict['pki_instance_id'] +\
+                                "," + "uid=" +\
+                                config.pki_master_dict['pki_admin_uid']\
+                                + "," + "e=" +\
+                                config.pki_master_dict['pki_admin_email'] +\
+                                "," + "o=" + "External CA"
+                       else:
+                            # PKI CA or Subordinate CA
+                            config.pki_master_dict['pki_admin_subject_dn'] =\
+                                "cn=" + "CA Administrator of Instance" + " " +\
+                                config.pki_master_dict['pki_instance_id'] +\
+                                "," + "uid=" +\
+                                config.pki_master_dict['pki_admin_uid']\
+                                + "," + "e=" +\
+                                config.pki_master_dict['pki_admin_email'] +\
+                                "," + "o=" +\
+                                config.pki_master_dict\
+                                ['pki_security_domain_name']
                     elif config.pki_master_dict['pki_subsystem'] == "KRA":
                         # PKI KRA
                         config.pki_master_dict['pki_admin_subject_dn'] =\
@@ -1928,10 +1922,7 @@ def compose_pki_master_dictionary():
                         if not len(config.pki_master_dict\
                                    ['pki_ca_signing_subject_dn']):
                             config.pki_master_dict['pki_ca_signing_subject_dn']\
-                                =  "cn=" + "External CA Signing Certificate" +\
-                                   "," + "o=" +\
-                                   config.pki_master_dict\
-                                   ['pki_security_domain_name']
+                                =  "cn=" + "External CA Signing Certificate"
                     elif config.str2bool(
                              config.pki_master_dict['pki_subordinate']):
                         # Subordinate CA
@@ -1998,10 +1989,7 @@ def compose_pki_master_dictionary():
                                    ['pki_ocsp_signing_subject_dn']):
                             config.pki_master_dict\
                             ['pki_ocsp_signing_subject_dn'] =\
-                                "cn=" + "External CA OCSP Signing Certificate"\
-                                + "," + "o=" +\
-                                config.pki_master_dict\
-                                ['pki_security_domain_name']
+                                "cn=" + "External CA OCSP Signing Certificate"
                     elif config.str2bool(
                              config.pki_master_dict['pki_subordinate']):
                         # Subordinate CA
@@ -2086,10 +2074,18 @@ def compose_pki_master_dictionary():
                     "," + "o=" +\
                     config.pki_master_dict['pki_security_domain_name']
             elif config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS:
-                config.pki_master_dict['pki_ssl_server_subject_dn'] =\
-                    "cn=" + config.pki_master_dict['pki_hostname'] +\
-                    "," + "o=" +\
-                    config.pki_master_dict['pki_security_domain_name']
+                if config.pki_master_dict['pki_subsystem'] == "CA" and\
+                   config.str2bool(config.pki_master_dict['pki_external']):
+                    # External CA
+                    config.pki_master_dict['pki_ssl_server_subject_dn'] =\
+                        "cn=" + config.pki_master_dict['pki_hostname'] +\
+                        "," + "o=" + "External CA"
+                else:
+                    # PKI or Cloned CA, KRA, OCSP, TKS, or Subordinate CA
+                    config.pki_master_dict['pki_ssl_server_subject_dn'] =\
+                        "cn=" + config.pki_master_dict['pki_hostname'] +\
+                        "," + "o=" +\
+                        config.pki_master_dict['pki_security_domain_name']
         config.pki_master_dict['pki_ssl_server_tag'] = "sslserver"
         if not len(config.pki_master_dict['pki_ssl_server_token']):
             config.pki_master_dict['pki_ssl_server_token'] =\
@@ -2156,10 +2152,7 @@ def compose_pki_master_dictionary():
                                config.pki_master_dict['pki_external']):
                             # External CA
                             config.pki_master_dict['pki_subsystem_subject_dn']\
-                                = "cn=" + "External CA Subsystem Certificate" +\
-                                  "," + "o=" +\
-                                  config.pki_master_dict\
-                                  ['pki_security_domain_name']
+                                = "cn=" + "External CA Subsystem Certificate"
                         elif config.str2bool(
                                  config.pki_master_dict['pki_subordinate']):
                             # Subordinate CA
@@ -2261,10 +2254,7 @@ def compose_pki_master_dictionary():
                             # External CA
                             config.pki_master_dict\
                             ['pki_audit_signing_subject_dn'] =\
-                                "cn=" + "External CA Audit Signing Certificate"\
-                                + "," + "o=" +\
-                                config.pki_master_dict\
-                                ['pki_security_domain_name']
+                                "cn=" + "External CA Audit Signing Certificate"
                         elif config.str2bool(
                                  config.pki_master_dict['pki_subordinate']):
                             # Subordinate CA
@@ -2392,6 +2382,31 @@ def compose_pki_master_dictionary():
                     if not len(config.pki_master_dict['pki_storage_token']):
                         config.pki_master_dict['pki_storage_token'] =\
                             "Internal Key Storage Token"
+        # Finalization name/value pairs
+        config.pki_master_dict['pki_deployment_cfg_replica'] =\
+            os.path.join(config.pki_master_dict['pki_subsystem_registry_path'],
+                         config.PKI_DEPLOYMENT_DEFAULT_CONFIGURATION_FILE)
+        config.pki_master_dict['pki_deployment_cfg_spawn_archive'] =\
+            config.pki_master_dict['pki_subsystem_archive_log_path'] + "/" +\
+            "spawn" + "_" +\
+            config.PKI_DEPLOYMENT_DEFAULT_CONFIGURATION_FILE + "." +\
+            config.pki_master_dict['pki_timestamp']
+        config.pki_master_dict['pki_deployment_cfg_respawn_archive'] =\
+            config.pki_master_dict['pki_subsystem_archive_log_path'] + "/" +\
+            "respawn" + "_" +\
+            config.PKI_DEPLOYMENT_DEFAULT_CONFIGURATION_FILE + "." +\
+            config.pki_master_dict['pki_timestamp']
+        config.pki_master_dict['pki_manifest'] =\
+            config.pki_master_dict['pki_subsystem_registry_path'] + "/" +\
+            "manifest"
+        config.pki_master_dict['pki_manifest_spawn_archive'] =\
+            config.pki_master_dict['pki_subsystem_archive_log_path'] + "/" +\
+            "spawn" + "_" + "manifest" + "." +\
+            config.pki_master_dict['pki_timestamp']
+        config.pki_master_dict['pki_manifest_respawn_archive'] =\
+            config.pki_master_dict['pki_subsystem_archive_log_path'] + "/" +\
+            "respawn" + "_" + "manifest" + "." +\
+            config.pki_master_dict['pki_timestamp']
     except OSError as exc:
         config.pki_log.error(log.PKI_OSERROR_1, exc,
                              extra=config.PKI_INDENTATION_LEVEL_2)
diff --git a/base/deploy/src/scriptlets/security_databases.py b/base/deploy/src/scriptlets/security_databases.py
index 8364d95..73919ce 100644
--- a/base/deploy/src/scriptlets/security_databases.py
+++ b/base/deploy/src/scriptlets/security_databases.py
@@ -22,6 +22,7 @@
 # PKI Deployment Imports
 import pkiconfig as config
 from pkiconfig import pki_master_dict as master
+from pkiconfig import pki_sensitive_dict as sensitive
 import pkihelper as util
 import pkimessages as log
 import pkiscriptlet
@@ -37,14 +38,14 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
         if not config.pki_dry_run_flag:
             util.password.create_password_conf(
                 master['pki_shared_password_conf'],
-                master['pki_pin'])
+                sensitive['pki_pin'])
             # Since 'certutil' does NOT strip the 'token=' portion of
             # the 'token=password' entries, create a temporary server 'pfile'
             # which ONLY contains the 'password' for the purposes of
             # allowing 'certutil' to generate the security databases
             util.password.create_password_conf(
                 master['pki_shared_pfile'],
-                master['pki_pin'], pin_sans_token=True)
+                sensitive['pki_pin'], pin_sans_token=True)
             util.file.modify(master['pki_shared_password_conf'])
             util.certutil.create_security_databases(
                 master['pki_database_path'],
@@ -91,14 +92,14 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
         else:
             util.password.create_password_conf(
                 master['pki_shared_password_conf'],
-                master['pki_pin'])
+                sensitive['pki_pin'])
             # Since 'certutil' does NOT strip the 'token=' portion of
             # the 'token=password' entries, create a temporary server 'pfile'
             # which ONLY contains the 'password' for the purposes of
             # allowing 'certutil' to generate the security databases
             util.password.create_password_conf(
                 master['pki_shared_pfile'],
-                master['pki_pin'], pin_sans_token=True)
+                sensitive['pki_pin'], pin_sans_token=True)
             util.certutil.create_security_databases(
                 master['pki_database_path'],
                 master['pki_cert_database'],
diff --git a/base/deploy/src/scriptlets/subsystem_layout.py b/base/deploy/src/scriptlets/subsystem_layout.py
index d9c597d..fc09fd5 100644
--- a/base/deploy/src/scriptlets/subsystem_layout.py
+++ b/base/deploy/src/scriptlets/subsystem_layout.py
@@ -38,6 +38,7 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
         util.directory.create(master['pki_subsystem_path'])
         # establish instance-based subsystem logs
         util.directory.create(master['pki_subsystem_log_path'])
+        util.directory.create(master['pki_subsystem_archive_log_path'])
         if master['pki_subsystem'] in config.PKI_SIGNED_AUDIT_SUBSYSTEMS:
             util.directory.create(master['pki_subsystem_signed_audit_log_path'])
         # establish instance-based subsystem configuration
@@ -96,6 +97,8 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
                             master['pki_subsystem_conf_link'])
         util.symlink.create(master['pki_subsystem_log_path'],
                             master['pki_subsystem_logs_link'])
+        util.symlink.create(master['pki_instance_registry_path'],
+                            master['pki_subsystem_registry_link'])
         return self.rv
 
     def respawn(self):
@@ -105,6 +108,7 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
         util.directory.modify(master['pki_subsystem_path'])
         # update instance-based subsystem logs
         util.directory.modify(master['pki_subsystem_log_path'])
+        util.directory.modify(master['pki_subsystem_archive_log_path'])
         if master['pki_subsystem'] in config.PKI_SIGNED_AUDIT_SUBSYSTEMS:
             util.directory.modify(master['pki_subsystem_signed_audit_log_path'])
         # update instance-based subsystem configuration
@@ -174,6 +178,7 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
         util.symlink.modify(master['pki_subsystem_database_link'])
         util.symlink.modify(master['pki_subsystem_conf_link'])
         util.symlink.modify(master['pki_subsystem_logs_link'])
+        util.symlink.modify(master['pki_subsystem_registry_link'])
         return self.rv
 
     def destroy(self):
@@ -187,6 +192,7 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
         # remove instance-based subsystem logs
         if master['pki_subsystem'] in config.PKI_SIGNED_AUDIT_SUBSYSTEMS:
             util.directory.delete(master['pki_subsystem_signed_audit_log_path'])
+        util.directory.delete(master['pki_subsystem_archive_log_path'])
         util.directory.delete(master['pki_subsystem_log_path'])
         # remove instance-based subsystem configuration
         util.directory.delete(master['pki_subsystem_configuration_path'])
-- 
1.7.10.4

