From d7f98cd28e7329f08413fd367be2d6eb15fe039f Mon Sep 17 00:00:00 2001 From: Endi Sukma Dewata Date: Tue, 18 Dec 2012 14:46:41 -0500 Subject: Added interactive subsystem installation. The pkispawn has been modified such that if there is no configuration file specified it will enter an interactive mode. Ticket #380 --- base/deploy/etc/default.cfg | 6 +- base/deploy/src/pkidestroy | 16 +- base/deploy/src/pkispawn | 62 +++++-- .../deploy/src/scriptlets/infrastructure_layout.py | 14 +- base/deploy/src/scriptlets/pkiconfig.py | 5 +- base/deploy/src/scriptlets/pkijython.py | 9 +- base/deploy/src/scriptlets/pkiparser.py | 190 ++++++++++++--------- 7 files changed, 175 insertions(+), 127 deletions(-) diff --git a/base/deploy/etc/default.cfg b/base/deploy/etc/default.cfg index d99faf2c4..00f68ee34 100644 --- a/base/deploy/etc/default.cfg +++ b/base/deploy/etc/default.cfg @@ -57,12 +57,12 @@ destroy_scriplets= # case someone wants to override them in their config file. # # Tomcat instances: -# pki_instance_name=pki_tomcat +# pki_instance_name=pki-tomcat # pki_https_port=8443 # pki_http_port=8080 # # Apache instances: -# pki_instance_name=pki_tomcat +# pki_instance_name=pki-apache # pki_https_port=443 # pki_http_port=80 @@ -125,7 +125,7 @@ pki_client_pkcs12_password_conf=%(pki_client_subsystem_dir)s/pkcs12_password.con pki_client_cert_database=%(pki_client_database_dir)s/cert8.db pki_client_key_database=%(pki_client_database_dir)s/key3.db pki_client_secmod_database=%(pki_client_database_dir)s/secmod.db -pki_client_admin_cert=%(pki_subsystem_type)s_admin.cert +pki_client_admin_cert=%(pki_client_dir)s/%(pki_subsystem_type)s_admin.cert pki_source_conf_path=/usr/share/pki/%(pki_subsystem_type)s/conf pki_source_setup_path=/usr/share/pki/setup pki_source_server_path=/usr/share/pki/server/conf diff --git a/base/deploy/src/pkidestroy b/base/deploy/src/pkidestroy index edb57e9ac..6014636b8 100755 --- a/base/deploy/src/pkidestroy +++ b/base/deploy/src/pkidestroy @@ -134,7 +134,7 @@ def main(argv): config.pki_subsystem.lower() + "/" +\ config.USER_DEPLOYMENT_CONFIGURATION - parser.validate() + parser.initialize() # Enable 'pkidestroy' logging. config.pki_log_dir = config.pki_root_prefix +\ @@ -161,20 +161,6 @@ def main(argv): extra=config.PKI_INDENTATION_LEVEL_0) sys.exit(1) - # NEVER print out 'sensitive' name/value pairs!!! - config.pki_log.debug(log.PKI_DICTIONARY_DEFAULT, - extra=config.PKI_INDENTATION_LEVEL_0) - config.pki_log.debug(pkilogging.format(config.pki_default_dict), - extra=config.PKI_INDENTATION_LEVEL_0) - config.pki_log.debug(log.PKI_DICTIONARY_WEB_SERVER, - extra=config.PKI_INDENTATION_LEVEL_0) - config.pki_log.debug(pkilogging.format(config.pki_web_server_dict), - extra=config.PKI_INDENTATION_LEVEL_0) - config.pki_log.debug(log.PKI_DICTIONARY_SUBSYSTEM, - extra=config.PKI_INDENTATION_LEVEL_0) - config.pki_log.debug(pkilogging.format(config.pki_subsystem_dict), - extra=config.PKI_INDENTATION_LEVEL_0) - # Combine the various sectional dictionaries into a PKI master dictionary parser.compose_pki_master_dictionary() config.pki_master_dict['pki_destroy_log'] = config.pki_log_dir + "/" +\ diff --git a/base/deploy/src/pkispawn b/base/deploy/src/pkispawn index f64d79575..a6985fe48 100755 --- a/base/deploy/src/pkispawn +++ b/base/deploy/src/pkispawn @@ -52,6 +52,10 @@ error was: def main(argv): "main entry point" + print "PKI Subsystem Installation" + print "--------------------------" + print + config.pki_deployment_executable = os.path.basename(argv[0]) # Only run this program as "root". @@ -96,7 +100,7 @@ def main(argv): parser.mandatory.add_argument('-f', dest='user_deployment_cfg', action='store', - nargs=1, required=True, metavar='', + nargs=1, metavar='', help='configuration filename ' '(MUST specify complete path)') @@ -109,12 +113,46 @@ def main(argv): config.default_deployment_cfg = config.PKI_DEPLOYMENT_DEFAULT_CONFIGURATION_FILE # -f - config.user_deployment_cfg = str(args.user_deployment_cfg).strip('[\']') + if not args.user_deployment_cfg is None: + config.user_deployment_cfg = str(args.user_deployment_cfg).strip('[\']') # -u config.pki_update_flag = args.pki_update_flag - parser.validate() + if config.user_deployment_cfg is None: + config.pki_subsystem = 'CA' + value = raw_input('Subsystem type [' + config.pki_subsystem + ']: ') + if len(value) > 0: + config.pki_subsystem = value + + parser.initialize() + + if config.user_deployment_cfg is None: + parser.read_text('DEFAULT', 'pki_instance_name', 'Instance name') + parser.read_text(config.pki_subsystem, 'pki_http_port', 'HTTP Port') + parser.read_text(config.pki_subsystem, 'pki_https_port', 'Secure HTTP port') + parser.read_text(config.pki_subsystem, 'pki_admin_uid', config.pki_subsystem + ' admin UID') + + admin_password = parser.read_password(config.pki_subsystem, 'pki_admin_password', config.pki_subsystem + ' admin password') + parser.pki_config.set(config.pki_subsystem, 'pki_backup_password', admin_password) + parser.pki_config.set(config.pki_subsystem, 'pki_client_database_password', admin_password) + parser.pki_config.set(config.pki_subsystem, 'pki_client_pkcs12_password', admin_password) + + parser.read_text(config.pki_subsystem, 'pki_client_admin_cert', config.pki_subsystem + ' admin certificate') + + parser.read_text(config.pki_subsystem, 'pki_ds_hostname', 'Directory server hostname') + parser.read_text(config.pki_subsystem, 'pki_ds_ldap_port', 'Directory server port') + parser.read_text(config.pki_subsystem, 'pki_ds_base_dn', 'Directory server base DN') + parser.read_text(config.pki_subsystem, 'pki_ds_bind_dn', 'Directory server bind DN') + parser.read_password(config.pki_subsystem, 'pki_ds_password', 'Directory server password') + + parser.read_text(config.pki_subsystem, 'pki_security_domain_name', 'Security domain name') + if config.pki_subsystem != "CA": + parser.read_text(config.pki_subsystem, 'pki_security_domain_hostname', 'Security domain hostname') + parser.read_text(config.pki_subsystem, 'pki_security_domain_https_port', 'Security domain secure HTTP port') + parser.read_text(config.pki_subsystem, 'pki_security_domain_user', 'Security domain user') + parser.read_password(config.pki_subsystem, 'pki_security_domain_password', 'Security domain password') + parser.read_text(config.pki_subsystem, 'pki_admin_cert_file', 'Security domain certificate') if not os.path.exists(config.PKI_DEPLOYMENT_SOURCE_ROOT +\ "/" + config.pki_subsystem.lower()): @@ -161,20 +199,6 @@ def main(argv): extra=config.PKI_INDENTATION_LEVEL_0) sys.exit(1) - # NEVER print out 'sensitive' name/value pairs!!! - config.pki_log.debug(log.PKI_DICTIONARY_DEFAULT, - extra=config.PKI_INDENTATION_LEVEL_0) - config.pki_log.debug(pkilogging.format(config.pki_default_dict), - extra=config.PKI_INDENTATION_LEVEL_0) - config.pki_log.debug(log.PKI_DICTIONARY_WEB_SERVER, - extra=config.PKI_INDENTATION_LEVEL_0) - config.pki_log.debug(pkilogging.format(config.pki_web_server_dict), - extra=config.PKI_INDENTATION_LEVEL_0) - config.pki_log.debug(log.PKI_DICTIONARY_SUBSYSTEM, - extra=config.PKI_INDENTATION_LEVEL_0) - config.pki_log.debug(pkilogging.format(config.pki_subsystem_dict), - extra=config.PKI_INDENTATION_LEVEL_0) - # Read in the PKI slots configuration file. parser.compose_pki_slots_dictionary() config.pki_log.debug(log.PKI_DICTIONARY_SLOTS, @@ -184,6 +208,7 @@ def main(argv): # Combine the various sectional dictionaries into a PKI master dictionary parser.compose_pki_master_dictionary() + if not config.pki_update_flag: config.pki_master_dict['pki_spawn_log'] = config.pki_log_dir + "/" +\ config.pki_log_name @@ -214,6 +239,9 @@ def main(argv): config.pki_log.debug(pkilogging.format(config.pki_master_dict), extra=config.PKI_INDENTATION_LEVEL_0) + print + print "Installation complete." + # PKI Deployment Entry Point if __name__ == "__main__": diff --git a/base/deploy/src/scriptlets/infrastructure_layout.py b/base/deploy/src/scriptlets/infrastructure_layout.py index 947fbcdfe..9b47f2b95 100644 --- a/base/deploy/src/scriptlets/infrastructure_layout.py +++ b/base/deploy/src/scriptlets/infrastructure_layout.py @@ -58,8 +58,18 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet): util.directory.create(master['pki_subsystem_registry_path']) util.file.copy(master['pki_default_deployment_cfg'], master['pki_default_deployment_cfg_replica']) - util.file.copy(master['pki_user_deployment_cfg'], - master['pki_user_deployment_cfg_replica']) + + if master['pki_user_deployment_cfg']: + util.file.copy(master['pki_user_deployment_cfg'], + master['pki_user_deployment_cfg_replica']) + else: + with open(master['pki_user_deployment_cfg_replica'], 'w') as f: + f.write('[DEFAULT]\n') + f.write('pki_instance_name=' + master['pki_instance_name'] + '\n') + f.write('[' + master['pki_subsystem'] + ']\n') + f.write('pki_admin_password=' + master['pki_admin_password'] + '\n') + f.write('pki_ds_password=' + master['pki_ds_password'] + '\n') + # establish top-level infrastructure, instance, and subsystem # base directories and create the "registry" symbolic link that # the "pkidestroy" executable relies upon diff --git a/base/deploy/src/scriptlets/pkiconfig.py b/base/deploy/src/scriptlets/pkiconfig.py index 4a884617c..cdd671c91 100644 --- a/base/deploy/src/scriptlets/pkiconfig.py +++ b/base/deploy/src/scriptlets/pkiconfig.py @@ -180,10 +180,7 @@ pki_console_log_level = None # PKI Deployment Global Dictionaries -pki_default_dict = None -pki_web_server_dict = None -pki_subsystem_dict = None -pki_master_dict = None +pki_master_dict = {} pki_slots_dict = None pki_master_jython_dict = None diff --git a/base/deploy/src/scriptlets/pkijython.py b/base/deploy/src/scriptlets/pkijython.py index fac352fdb..59e52f15c 100644 --- a/base/deploy/src/scriptlets/pkijython.py +++ b/base/deploy/src/scriptlets/pkijython.py @@ -560,9 +560,7 @@ class rest_client: javasystem.out.println(log.PKI_JYTHON_RESPONSE_ADMIN_CERT +\ " " + admin_cert) # Store the Administration Certificate in a file - admin_cert_file = os.path.join( - master['pki_client_dir'], - master['pki_client_admin_cert']) + admin_cert_file = master['pki_client_admin_cert'] admin_cert_bin_file = admin_cert_file + ".der" javasystem.out.println(log.PKI_JYTHON_ADMIN_CERT_SAVE +\ " " + "'" + admin_cert_file + "'") @@ -612,11 +610,12 @@ class rest_client: javasystem.out.println( log.PKI_JYTHON_ADMIN_CERT_IMPORT +\ " " + "'" + command + "'") + print "pos 4: " + command os.system(command) # create directory for p12 file if it does not exist - self.mkdirs(os.path.dirname( - master['pki_client_admin_cert_p12'])) + # self.mkdirs(os.path.dirname( + # master['pki_client_admin_cert_p12'])) # Export the Administration Certificate from the # client NSS security database into a PKCS #12 file diff --git a/base/deploy/src/scriptlets/pkiparser.py b/base/deploy/src/scriptlets/pkiparser.py index ba4f376da..a9ac2d1b3 100644 --- a/base/deploy/src/scriptlets/pkiparser.py +++ b/base/deploy/src/scriptlets/pkiparser.py @@ -22,6 +22,7 @@ # System Imports import ConfigParser import argparse +import getpass import logging import os import random @@ -57,7 +58,7 @@ class PKIConfigParser: self.mandatory.add_argument('-s', dest='pki_subsystem', action='store', nargs=1, choices=config.PKI_SUBSYSTEMS, - required=True, metavar='', + metavar='', help='where is ' 'CA, KRA, OCSP, RA, TKS, or TPS') # Establish 'Optional' command-line options @@ -122,7 +123,7 @@ class PKIConfigParser: return args - def validate(self): + def initialize(self): # Validate command-line options if len(config.pki_root_prefix) > 0: @@ -145,16 +146,57 @@ class PKIConfigParser: self.arg_parser.print_help() self.arg_parser.exit(-1); - # verify user configuration file exists - if not os.path.exists(config.user_deployment_cfg) or\ - not os.path.isfile(config.user_deployment_cfg): - print "ERROR: " +\ - log.PKI_FILE_MISSING_OR_NOT_A_FILE_1 %\ - config.user_deployment_cfg - print - self.arg_parser.print_help() - self.arg_parser.exit(-1); - + if config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS: + default_instance_name = 'pki-tomcat' + default_http_port = '8080' + default_https_port = '8443' + else: + default_instance_name = 'pki-apache' + default_http_port = '80' + default_https_port = '443' + + # RESTEasy + resteasy_lib = subprocess.check_output(\ + 'source /etc/pki/pki.conf && echo $RESTEASY_LIB', + shell=True).strip() + + # arch dependent libpath + if config.pki_architecture == 64: + arch_java_lib = '/usr/lib64/java' + else: + arch_java_lib = '/usr/lib/java' + + self.pki_config = ConfigParser.SafeConfigParser({ + 'pki_instance_name': default_instance_name, + 'pki_http_port': default_http_port, + 'pki_https_port': default_https_port, + 'pki_dns_domainname': config.pki_dns_domainname, + 'pki_subsystem' : config.pki_subsystem, + 'pki_subsystem_type': config.pki_subsystem.lower(), + 'pki_root_prefix' : config.pki_root_prefix, + 'resteasy_lib': resteasy_lib, + 'arch_java_lib': arch_java_lib, + 'home_dir': os.path.expanduser("~"), + 'pki_hostname': config.pki_hostname}) + + # Make keys case-sensitive! + self.pki_config.optionxform = str + + with open(config.default_deployment_cfg) as f: + self.pki_config.readfp(f) + + self.flatten_master_dict() + + if config.user_deployment_cfg: + # verify user configuration file exists + if not os.path.exists(config.user_deployment_cfg) or\ + not os.path.isfile(config.user_deployment_cfg): + print "ERROR: " +\ + log.PKI_FILE_MISSING_OR_NOT_A_FILE_1 %\ + config.user_deployment_cfg + print + parser.arg_parser.print_help() + parser.arg_parser.exit(-1); # The following code is based heavily upon # "http://www.decalage.info/en/python/configparser" @@ -179,84 +221,72 @@ class PKIConfigParser: f.close() return values + def read_text(self, section, property, message): + default = config.pki_master_dict[property] + if default: + message = message + ' [' + default + ']' + value = raw_input(message + ': ') + if len(value) == 0: + value = default + self.pki_config.set(section, property, value) + self.flatten_master_dict() + return value + + def read_password(self, section, property, message): + value = '' + while len(value) == 0: + value = getpass.getpass(prompt=message + ': ') + self.pki_config.set(section, property, value) + self.flatten_master_dict() + return value def read_pki_configuration_file(self): "Read configuration file sections into dictionaries" rv = 0 try: - if config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS: - default_instance_name = 'pki-tomcat' - default_http_port = '8080' - default_https_port = '8443' - else: - default_instance_name = 'pki-apache' - default_http_port = '80' - default_https_port = '443' - - # RESTEasy - resteasy_lib = subprocess.check_output(\ - 'source /etc/pki/pki.conf && echo $RESTEASY_LIB', - shell=True).strip() - - # arch dependent libpath - if config.pki_architecture == 64: - arch_java_lib = '/usr/lib64/java' - else: - arch_java_lib = '/usr/lib/java' - - predefined_dict = {'pki_instance_name': default_instance_name, - 'pki_http_port': default_http_port, - 'pki_https_port': default_https_port, - 'pki_dns_domainname': config.pki_dns_domainname, - 'pki_subsystem' : config.pki_subsystem, - 'pki_subsystem_type': config.pki_subsystem.lower(), - 'pki_root_prefix' : config.pki_root_prefix, - 'resteasy_lib': resteasy_lib, - 'arch_java_lib': arch_java_lib, - 'home_dir': os.path.expanduser("~"), - 'pki_hostname': config.pki_hostname} - - self.pki_config = ConfigParser.SafeConfigParser(predefined_dict) + # print pkilogging.format(self.defaults) + + # self.pki_config = ConfigParser.SafeConfigParser(self.defaults) # Make keys case-sensitive! - self.pki_config.optionxform = str - self.pki_config.read([ - config.default_deployment_cfg, - config.user_deployment_cfg]) - config.pki_default_dict = dict(self.pki_config.items('DEFAULT')) - pkilogging.sensitive_parameters = config.pki_default_dict['sensitive_parameters'].split() - if config.pki_subsystem == "CA": - config.pki_web_server_dict = dict(self.pki_config.items('Tomcat')) - config.pki_subsystem_dict = dict(self.pki_config.items('CA')) - elif config.pki_subsystem == "KRA": - config.pki_web_server_dict = dict(self.pki_config.items('Tomcat')) - config.pki_subsystem_dict = dict(self.pki_config.items('KRA')) - elif config.pki_subsystem == "OCSP": - config.pki_web_server_dict = dict(self.pki_config.items('Tomcat')) - config.pki_subsystem_dict = dict(self.pki_config.items('OCSP')) - elif config.pki_subsystem == "RA": - config.pki_web_server_dict = dict(self.pki_config.items('Apache')) - config.pki_subsystem_dict = dict(self.pki_config.items('RA')) - elif config.pki_subsystem == "TKS": - config.pki_web_server_dict = dict(self.pki_config.items('Tomcat')) - config.pki_subsystem_dict = dict(self.pki_config.items('TKS')) - elif config.pki_subsystem == "TPS": - config.pki_web_server_dict = dict(self.pki_config.items('Apache')) - config.pki_subsystem_dict = dict(self.pki_config.items('TPS')) - # Insert empty record into dictionaries for "pretty print" statements - # NEVER print "sensitive" key value pairs!!! - config.pki_default_dict[0] = None - config.pki_web_server_dict[0] = None - config.pki_subsystem_dict[0] = None + # self.pki_config.optionxform = str + # with open(config.default_deployment_cfg) as f: + # self.pki_config.readfp(f) + + if config.user_deployment_cfg: + print 'Reading configuration file ' + config.user_deployment_cfg + '.' + self.pki_config.read([config.user_deployment_cfg]) + except ConfigParser.ParsingError, err: print err rv = err return rv + def flatten_master_dict(self): + config.pki_master_dict.update(__name__="PKI Master Dictionary") + + default_dict = dict(self.pki_config.items('DEFAULT')) + default_dict[0] = None + # print 'Default: ' + pkilogging.format(default_dict) + config.pki_master_dict.update(default_dict) + + if config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS: + web_server_dict = dict(self.pki_config.items('Tomcat')) + else: + web_server_dict = dict(self.pki_config.items('Apache')) + web_server_dict[0] = None + # print 'Web: ' + pkilogging.format(web_server_dict) + config.pki_master_dict.update(web_server_dict) + + subsystem_dict = dict(self.pki_config.items(config.pki_subsystem)) + subsystem_dict[0] = None + # print 'Subsystem: ' + pkilogging.format(subsystem_dict) + config.pki_master_dict.update(subsystem_dict) + + def compose_pki_master_dictionary(self): "Create a single master PKI dictionary from the sectional dictionaries" try: - config.pki_master_dict = dict() # 'pkispawn'/'pkirespawn'/'pkidestroy' name/value pairs config.pki_master_dict['pki_deployment_executable'] =\ config.pki_deployment_executable @@ -280,12 +310,10 @@ class PKIConfigParser: random.randint(pin_low, pin_high) config.pki_master_dict['pki_client_pin'] =\ random.randint(pin_low, pin_high) - # Configuration file name/value pairs - # NEVER add "sensitive" key value pairs to the master dictionary!!! - config.pki_master_dict.update(config.pki_default_dict) - config.pki_master_dict.update(config.pki_web_server_dict) - config.pki_master_dict.update(config.pki_subsystem_dict) - config.pki_master_dict.update(__name__="PKI Master Dictionary") + + self.flatten_master_dict() + + pkilogging.sensitive_parameters = config.pki_master_dict['sensitive_parameters'].split() # PKI Target (slot substitution) name/value pairs config.pki_master_dict['pki_target_cs_cfg'] =\ -- cgit