def execute(self, argv): try: opts, args = getopt.gnu_getopt(argv, 'i:v', [ 'instance=', 'input=', 'verbose', 'debug', 'help']) except getopt.GetoptError as e: logger.error(e) self.print_help() sys.exit(1) instance_name = 'pki-tomcat' cert_file = None for o, a in opts: if o in ('-i', '--instance'): instance_name = a elif o == '--input': cert_file = a elif o == '--debug': logging.getLogger().setLevel(logging.DEBUG) elif o in ('-v', '--verbose'): logging.getLogger().setLevel(logging.INFO) elif o == '--help': self.print_help() sys.exit() else: logger.error('option %s not recognized', o) self.print_help() sys.exit(1) if len(args) < 1: logger.error('Missing cert ID.') self.print_help() sys.exit(1) cert_id = args[0] instance = pki.server.instance.PKIInstance(instance_name) if not instance.exists(): logger.error('Invalid instance %s.', instance_name) sys.exit(1) # Load the instance. Default: pki-tomcat instance.load() try: # Load the cert into NSS db and update all corresponding subsystem's CS.cfg instance.cert_import(cert_id, cert_file) except pki.server.PKIServerException as e: logger.error(str(e)) sys.exit(1)
def execute(self, argv): logging.getLogger().setLevel(logging.INFO) try: opts, _ = getopt.gnu_getopt(argv, 'i:p:v', [ 'instance=', 'cert=', 'extra-cert=', 'agent-uid=', 'ldapi-socket=', 'ldap-url=', 'port=', 'verbose', 'debug', 'help', ]) except getopt.GetoptError as e: logger.error(e) self.print_help() sys.exit(1) instance_name = 'pki-tomcat' all_certs = True fix_certs = [] extra_certs = [] agent_uid = None ldap_url = None use_ldapi = False port = '8443' for o, a in opts: if o in ('-i', '--instance'): instance_name = a elif o == '--cert': all_certs = False fix_certs.append(a) elif o == '--extra-cert': try: int(a) except ValueError: logger.error('--extra-cert requires serial number as integer') sys.exit(1) all_certs = False extra_certs.append(a) elif o == '--agent-uid': agent_uid = a elif o == '--ldapi-socket': if ldap_url is not None: logger.error('--ldapi-socket cannot be used with --ldap-url') sys.exit(1) use_ldapi = True ldap_url = 'ldapi://{}'.format(quote(a, safe='')) elif o == '--ldap-url': if use_ldapi: logger.error('--ldap-url cannot be used with --ldapi-socket') sys.exit(1) ldap_url = a elif o in ('-p', '--port'): port = a try: n = int(port) if n < 1 or n > 65535: raise ValueError except ValueError: logger.error('-p, --port requires a valid port number as integer') sys.exit(1) elif o == '--debug': logging.getLogger().setLevel(logging.DEBUG) elif o in ('-v', '--verbose'): logging.getLogger().setLevel(logging.INFO) elif o == '--help': self.print_help() sys.exit() else: logger.error('option %s not recognized', o) self.print_help() sys.exit(1) instance = pki.server.instance.PKIInstance(instance_name) if not instance.exists(): logger.error('Invalid instance %s.', instance_name) sys.exit(1) if not agent_uid: logger.error('Must specify --agent-uid') sys.exit(1) if agent_uid == "pkidbuser": logger.error('\'pkidbuser\' cannot be used.') sys.exit(1) instance.load() # 1. Make a list of certs to fix OR use the list provided through CLI options if all_certs: # TODO: Identify only certs that are EXPIRED or ALMOST EXPIRED for subsystem in instance.get_subsystems(): # Retrieve the subsystem's system certificate certs = subsystem.find_system_certs() # Iterate on all subsystem's system certificate to prepend # subsystem name to the ID for cert in certs: if cert['id'] != 'sslserver' and cert['id'] != 'subsystem': cert['id'] = subsystem.name + '_' + cert['id'] # Append only unique certificates to other subsystem certificate list # ca_signing isn't supported yet if cert['id'] in fix_certs or cert['id'] == 'ca_signing': continue fix_certs.append(cert['id']) logger.info('Fixing the following system certs: %s', fix_certs) logger.info('Renewing the following additional certs: %s', extra_certs) # Get the CA subsystem and find out Base DN. ca_subsystem = instance.get_subsystem('ca') basedn = ca_subsystem.get_db_config()['internaldb.basedn'] dbuser_dn = 'uid=pkidbuser,ou=people,{}'.format(basedn) agent_dn = 'uid={},ou=people,{}'.format(agent_uid, basedn) dm_pass = '' if not use_ldapi: # Prompt for DM password dm_pass = getpass.getpass(prompt='Enter Directory Manager password: '******'s up logger.info('Stopping the instance to proceed with system cert renewal') instance.stop() # 3. Find the subsystem and disable Self-tests try: # Placeholder used to hold subsystems whose selftest have been turned off # Note: This is initialized as a set to avoid duplicates # Example of duplicates: # fix_certs = [ca_ocsp_signing, ca_audit_signing] -> will add 'ca' entry twice target_subsys = set() if 'sslserver' in fix_certs or 'subsystem' in fix_certs: # If the cert is either sslserver/subsystem, disable selftest for all # subsystems since all subsystems use these 2 certs. target_subsys = set(instance.get_subsystems()) else: for cert_id in fix_certs: # Since we already filtered sslserver/subsystem, we can be quite sure # that this split will definitely be of form: <subsys>_<cert_tag> subsystem_name = cert_id.split('_', 1)[0] subsystem = instance.get_subsystem(subsystem_name) # If the subsystem is wrong, stop the process if not subsystem: logger.error('No %s subsystem in instance %s.', subsystem_name, instance_name) sys.exit(1) target_subsys.add(subsystem) if len(extra_certs) > 0: target_subsys.add(ca_subsystem) # Generate new password for agent account agent_pass = gen_random_password() with write_temp_file(agent_pass.encode('utf8')) as agent_pass_file, \ write_temp_file(dm_pass.encode('utf8')) as dm_pass_file, \ ldap_password_authn( instance, target_subsys, dbuser_dn, ldap_url, use_ldapi, dm_pass_file), \ suppress_selftest(target_subsys): # Verify LDAP connection and DM password cmd = ['ldapsearch'] + \ ldap_conn_args(ldap_url, use_ldapi, dm_pass_file) + \ ['-s', 'base', '-b', basedn, '1.1'] try: subprocess.check_output(cmd) except subprocess.CalledProcessError: logger.error("Failed to connect/authenticate to LDAP at '%s'", ldap_url) sys.exit(1) # Reset agent password logger.info('Resetting password for %s', agent_dn) ldappasswd(ldap_url, use_ldapi, dm_pass_file, agent_dn, agent_pass_file) # 4. Bring up the server using a temp SSL cert if the sslcert is expired if 'sslserver' in fix_certs: # 4a. Create temp SSL cert logger.info('Creating a temporary sslserver cert') instance.cert_create(cert_id='sslserver', temp_cert=True) # 4b. Delete the existing SSL Cert logger.debug('Removing sslserver cert from instance') instance.cert_del('sslserver') # 4d. Import the temp sslcert into the instance logger.debug('Importing temp sslserver cert') instance.cert_import('sslserver') with start_stop(instance): # Place renewal request for all certs in fix_certs for cert_id in fix_certs: logger.info('Requesting new cert for %s', cert_id) instance.cert_create( cert_id=cert_id, renew=True, username=agent_uid, password=agent_pass, secure_port=port) for serial in extra_certs: output = instance.cert_file('{}-renewed'.format(serial)) logger.info( 'Requesting new cert for %s; writing to %s', serial, output) try: instance.cert_create( serial=serial, renew=True, output=output, username=agent_uid, password=agent_pass, secure_port=port) except pki.PKIException as e: logger.error("Failed to renew certificate %s: %s", serial, e) # 8. Delete existing certs and then import the renewed system cert(s) for cert_id in fix_certs: # Delete the existing cert from the instance logger.debug('Removing old %s cert from instance %s', cert_id, instance_name) instance.cert_del(cert_id) # Import this new cert into the instance logger.debug('Importing new %s cert into instance %s', cert_id, instance_name) instance.cert_import(cert_id) # If subsystem cert was renewed and server was using # TLS auth, add the cert to pkidbuser entry if dbuser_dn and 'subsystem' in fix_certs: logger.info('Importing new subsystem cert into %s', dbuser_dn) with NamedTemporaryFile(mode='w+b') as der_file: # convert subsystem cert to DER subprocess.check_call([ 'openssl', 'x509', '-inform', 'PEM', '-outform', 'DER', '-in', instance.cert_file('subsystem'), '-out', der_file.name, ]) with write_temp_file( self.PKIDBUSER_LDIF_TEMPLATE .format(dn=dbuser_dn, der_file=der_file.name) .encode('utf-8') ) as ldif_file: # ldapmodify cmd = ['ldapmodify'] + \ ldap_conn_args(ldap_url, use_ldapi, dm_pass_file) + \ ['-f', ldif_file] subprocess.check_call(cmd) # 10. Bring up the server logger.info('Starting the instance with renewed certs') instance.start() except pki.server.PKIServerException as e: logger.error(str(e)) sys.exit(1)