def test_ch_dir_missing(self, chdir_mock, makedirs_mock, exists_mock): """Test ch_dir when the directory is missing.""" exists_mock.return_value = False fs_util.ch_dir("/tmp/dir") makedirs_mock.assert_called_once() chdir_mock.assert_called_once()
def test_ch_dir_present(self, chdir_mock, makedirs_mock, exists_mock): """Test ch_dir when the directory exists.""" exists_mock.return_value = True fs_util.ch_dir("/tmp/dir") makedirs_mock.assert_not_called() chdir_mock.assert_called_once()
def cmd_mkcert(workingdir, name): cwd = os.getcwd() try: fs_util.ch_dir(workingdir) priv = read_private() cacert = load_cert_by_path('cacert.crt') ca_pk = serialization.load_pem_private_key(priv[0]['ca'], password=None, backend=default_backend()) cert, pk = ca_impl.mk_signed_cert(cacert, ca_pk, name, priv[0]['lastserial'] + 1) with open('%s-cert.crt' % name, 'wb') as f: f.write(cert.public_bytes(serialization.Encoding.PEM)) priv[0][name] = pk.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption(), ) # increment serial number after successful creation priv[0]['lastserial'] += 1 write_private(priv) with os.fdopen( os.open("%s-private.pem" % name, os.O_WRONLY | os.O_CREAT, 0o600), 'wb') as f: f.write(priv[0][name]) with os.fdopen( os.open("%s-public.pem" % name, os.O_WRONLY | os.O_CREAT, 0o600), 'wb') as f: f.write(pk.public_key().public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo)) cc = load_cert_by_path('%s-cert.crt' % name) pubkey = cacert.public_key() pubkey.verify( cc.signature, cc.tbs_certificate_bytes, padding.PKCS1v15(), cc.signature_hash_algorithm, ) logger.info( f"Created certificate for name {name} successfully in {workingdir}" ) except crypto_exceptions.InvalidSignature: logger.error("ERROR: Cert does not validate against CA") finally: os.chdir(cwd)
def test_010_reg_agent_post(self): """Test registrar's POST /agents/{UUID} Interface""" global keyblob, tpm_instance, ek_tpm, aik_tpm contact_ip = "127.0.0.1" contact_port = 9002 tpm_instance = tpm_main.tpm() # Change CWD for TPM-related operations cwd = os.getcwd() fs_util.ch_dir(config.WORK_DIR) _ = secure_mount.mount() # Create a mTLS cert for testing global mtls_cert rsa_key = crypto.rsa_generate(2048) valid_util = datetime.datetime.utcnow() + datetime.timedelta(days=(360 * 5)) mtls_cert = crypto.generate_selfsigned_cert("TEST_CERT", rsa_key, valid_util).public_bytes( serialization.Encoding.PEM ) # Initialize the TPM with AIK (ekcert, ek_tpm, aik_tpm) = tpm_instance.tpm_init( self_activate=False, config_pw=config.get("cloud_agent", "tpm_ownerpassword") ) # Handle emulated TPMs if ekcert is None: if tpm_instance.is_emulator(): ekcert = "emulator" # Get back to our original CWD fs_util.ch_dir(cwd) data = {"ekcert": ekcert, "aik_tpm": aik_tpm, "ip": contact_ip, "port": contact_port, "mtls_cert": mtls_cert} if ekcert is None or ekcert == "emulator": data["ek_tpm"] = ek_tpm test_010_reg_agent_post = RequestsClient(tenant_templ.registrar_base_url, tls_enabled=False) response = test_010_reg_agent_post.post( f"/v{self.api_version}/agents/{tenant_templ.agent_uuid}", data=json.dumps(data), cert="", verify=False ) self.assertEqual(response.status_code, 200, "Non-successful Registrar agent Add return code!") json_response = response.json() # Ensure response is well-formed self.assertIn("results", json_response, "Malformed response body!") self.assertIn("blob", json_response["results"], "Malformed response body!") keyblob = json_response["results"]["blob"] self.assertIsNotNone(keyblob, "Malformed response body!")
def cmd_revoke(workingdir, name=None, serial=None): cwd = os.getcwd() try: fs_util.ch_dir(workingdir) priv = read_private() if name is not None and serial is not None: raise Exception( "You may not specify a cert and a serial at the same time") if name is None and serial is None: raise Exception("You must specify a cert or a serial to revoke") if name is not None: # load up the cert cert = load_cert_by_path(f'{name}-cert.crt') serial = cert.serial_number # convert serial to string serial = str(serial) # get the ca key cert and keys as strings with open('cacert.crt', encoding="utf-8") as f: cacert = f.read() ca_pk = priv[0]['ca'].decode('utf-8') if serial not in priv[0]['revoked_keys']: priv[0]['revoked_keys'].append(serial) crl = ca_impl.gencrl(priv[0]['revoked_keys'], cacert, ca_pk) write_private(priv) # write out the CRL to the disk if os.stat('cacrl.der').st_size: with open('cacrl.der', 'wb') as f: f.write(crl) convert_crl_to_pem("cacrl.der", "cacrl.pem") finally: os.chdir(cwd) return crl
def cmd_regencrl(workingdir): cwd = os.getcwd() try: fs_util.ch_dir(workingdir) priv = read_private() # get the ca key cert and keys as strings with open('cacert.crt', encoding="utf-8") as f: cacert = f.read() ca_pk = priv[0]['ca'].decode() crl = ca_impl.gencrl(priv[0]['revoked_keys'], cacert, ca_pk) write_private(priv) # write out the CRL to the disk with open('cacrl.der', 'wb') as f: f.write(crl) convert_crl_to_pem("cacrl.der", "cacrl.pem") finally: os.chdir(cwd) return crl
def cmd_listen(workingdir, cert_path): cwd = os.getcwd() try: fs_util.ch_dir(workingdir) # just load up the password for later read_private(True) serveraddr = ('', config.CRL_PORT) server = ThreadedCRLServer(serveraddr, CRLHandler) if os.path.exists('cacrl.der'): logger.info("Loading existing crl: %s", os.path.abspath("cacrl.der")) with open('cacrl.der', 'rb') as f: server.setcrl(f.read()) t = threading.Thread(target=server.serve_forever) logger.info("Hosting CRL on %s:%d", socket.getfqdn(), config.CRL_PORT) t.start() def check_expiration(): logger.info("checking CRL for expiration every hour") while True: # pylint: disable=R1702 try: if (os.path.exists('cacrl.der') and os.stat('cacrl.der').st_size): cmd = ('openssl', 'crl', '-inform', 'der', '-in', 'cacrl.der', '-text', '-noout') retout = cmd_exec.run(cmd)['retout'] for line in retout: line = line.strip() if line.startswith(b"Next Update:"): expire = datetime.datetime.strptime( line[13:].decode('utf-8'), "%b %d %H:%M:%S %Y %Z") # check expiration within 6 hours in1hour = datetime.datetime.utcnow() + datetime.timedelta(hours=6) if expire <= in1hour: logger.info( "Certificate to expire soon %s, re-issuing", expire) cmd_regencrl(workingdir) # check a little less than every hour time.sleep(3540) except KeyboardInterrupt: logger.info("TERM Signal received, shutting down...") # server.shutdown() break t2 = threading.Thread(target=check_expiration) t2.setDaemon(True) t2.start() def revoke_callback(revocation): json_meta = json.loads(revocation['meta_data']) serial = json_meta['cert_serial'] if revocation.get('type', None) != 'revocation' or serial is None: logger.error("Unsupported revocation message: %s", revocation) return logger.info("Revoking certificate: %s", serial) server.setcrl(cmd_revoke(workingdir, None, serial)) try: while True: try: revocation_notifier.await_notifications( revoke_callback, revocation_cert_path=cert_path) except Exception as e: logger.exception(e) logger.warning( "No connection to revocation server, retrying in 10s...") time.sleep(10) except KeyboardInterrupt: logger.info("TERM Signal received, shutting down...") server.shutdown() sys.exit() finally: os.chdir(cwd)
def cmd_certpkg(workingdir, name, insecure=False): cwd = os.getcwd() try: fs_util.ch_dir(workingdir) # zip up the crt, private key, and public key with open('cacert.crt', 'rb') as f: cacert = f.read() with open(f"{name}-public.pem", 'rb') as f: pub = f.read() with open(f"{name}-cert.crt", 'rb') as f: cert = f.read() with open('cacrl.der', 'rb') as f: crl = f.read() with open('cacrl.pem', 'rb') as f: crlpem = f.read() cert_obj = x509.load_pem_x509_certificate( data=cert, backend=default_backend(), ) serial = cert_obj.serial_number subject = cert_obj.subject.rfc4514_string() priv = read_private() private = priv[0][name] with open(f"{name}-private.pem", 'rb') as f: prot_priv = f.read() # no compression to avoid extraction errors in tmpfs sf = io.BytesIO() with zipfile.ZipFile(sf, 'w', compression=zipfile.ZIP_STORED) as f: f.writestr(f"{name}-public.pem", pub) f.writestr(f"{name}-cert.crt", cert) f.writestr(f"{name}-private.pem", private) f.writestr('cacert.crt', cacert) f.writestr('cacrl.der', crl) f.writestr('cacrl.pem', crlpem) pkg = sf.getvalue() if insecure: logger.warning( "Unprotected private keys in cert package being written to disk") with open(f'{name}-pkg.zip', 'wb') as f: f.write(pkg) else: # actually output the package to disk with a protected private key with zipfile.ZipFile(f'{name}-pkg.zip', 'w', compression=zipfile.ZIP_STORED) as f: f.writestr(f"{name}-public.pem", pub) f.writestr(f"{name}-cert.crt", cert) f.writestr(f"{name}-private.pem", prot_priv) f.writestr('cacert.crt', cacert) f.writestr('cacrl.der', crl) f.writestr('cacrl.pem', crlpem) logger.info("Creating cert package for %s in %s-pkg.zip", name, name) return pkg, serial, subject finally: os.chdir(cwd)
def cmd_init(workingdir): cwd = os.getcwd() try: fs_util.ch_dir(workingdir) rmfiles("*.pem") rmfiles("*.crt") rmfiles("*.zip") rmfiles("*.der") rmfiles("private.yml") cacert, ca_pk, _ = ca_impl.mk_cacert() # pylint: disable=W0632 priv = read_private() # write out keys with open('cacert.crt', 'wb') as f: f.write(cacert.public_bytes(serialization.Encoding.PEM)) priv[0]['ca'] = ca_pk.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption(), ) # store the last serial number created. # the CA is always serial # 1 priv[0]['lastserial'] = 1 write_private(priv) with os.fdopen(os.open("ca-public.pem", os.O_WRONLY | os.O_CREAT, 0o600), 'wb') as f: f.write(ca_pk.public_key().public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo )) # generate an empty crl cacert_str = cacert.public_bytes(serialization.Encoding.PEM).decode() crl = ca_impl.gencrl([], cacert_str, priv[0]['ca'].decode()) if isinstance(crl, str): crl = crl.encode('utf-8') with open('cacrl.der', 'wb') as f: f.write(crl) convert_crl_to_pem("cacrl.der", "cacrl.pem") # Sanity checks... cac = load_cert_by_path('cacert.crt') pubkey = cacert.public_key() pubkey.verify( cac.signature, cac.tbs_certificate_bytes, padding.PKCS1v15(), cac.signature_hash_algorithm, ) logger.info("CA certificate created successfully in %s", workingdir) except crypto_exceptions.InvalidSignature: logger.error("ERROR: Cert does not self validate") finally: os.chdir(cwd)
def main(): for ML in [config.MEASUREDBOOT_ML, config.IMA_ML]: if not os.access(ML, os.F_OK): logger.warning( 'Measurement list path %s not accessible by agent. Any attempt to instruct it to access this path - via "keylime_tenant" CLI - will result in agent process dying', ML, ) ima_log_file = None if os.path.exists(config.IMA_ML): ima_log_file = open(config.IMA_ML, "r", encoding="utf-8") # pylint: disable=consider-using-with tpm_log_file_data = None if os.path.exists(config.MEASUREDBOOT_ML): with open(config.MEASUREDBOOT_ML, "rb") as tpm_log_file: tpm_log_file_data = base64.b64encode(tpm_log_file.read()) if config.get("cloud_agent", "agent_uuid") == "dmidecode": if os.getuid() != 0: raise RuntimeError( "agent_uuid is configured to use dmidecode, but current process is not running as root." ) cmd = ["which", "dmidecode"] ret = cmd_exec.run(cmd, raiseOnError=False) if ret["code"] != 0: raise RuntimeError( "agent_uuid is configured to use dmidecode, but it's is not found on the system." ) # initialize the tmpfs partition to store keys if it isn't already available secdir = secure_mount.mount() # Now that operations requiring root privileges are done, drop privileges # if 'run_as' is available in the configuration. if os.getuid() == 0: run_as = config.get("cloud_agent", "run_as", fallback="") if run_as != "": user_utils.chown(secdir, run_as) user_utils.change_uidgid(run_as) logger.info("Dropped privileges to %s", run_as) else: logger.warning( "Cannot drop privileges since 'run_as' is empty or missing in keylime.conf agent section." ) # Instanitate TPM class instance_tpm = tpm() # get params for initialization registrar_ip = config.get("cloud_agent", "registrar_ip") registrar_port = config.get("cloud_agent", "registrar_port") # get params for the verifier to contact the agent contact_ip = os.getenv("KEYLIME_AGENT_CONTACT_IP", None) if contact_ip is None and config.has_option("cloud_agent", "agent_contact_ip"): contact_ip = config.get("cloud_agent", "agent_contact_ip") contact_port = os.getenv("KEYLIME_AGENT_CONTACT_PORT", None) if contact_port is None and config.has_option("cloud_agent", "agent_contact_port"): contact_port = config.get("cloud_agent", "agent_contact_port", fallback="invalid") # change dir to working dir fs_util.ch_dir(config.WORK_DIR) # set a conservative general umask os.umask(0o077) # initialize tpm (ekcert, ek_tpm, aik_tpm) = instance_tpm.tpm_init( self_activate=False, config_pw=config.get("cloud_agent", "tpm_ownerpassword") ) # this tells initialize not to self activate the AIK # Warn if kernel version is <5.10 and another algorithm than SHA1 is used, # because otherwise IMA will not work kernel_version = tuple(platform.release().split("-")[0].split(".")) if tuple(map(int, kernel_version)) < ( 5, 10, 0) and instance_tpm.defaults["hash"] != algorithms.Hash.SHA1: logger.warning( "IMA attestation only works on kernel versions <5.10 with SHA1 as hash algorithm. " 'Even if ascii_runtime_measurements shows "%s" as the ' "algorithm, it might be just padding zeros", (instance_tpm.defaults["hash"]), ) if ekcert is None and instance_tpm.is_emulator(): ekcert = "emulator" # now we need the UUID try: agent_uuid = config.get("cloud_agent", "agent_uuid") except configparser.NoOptionError: agent_uuid = None if agent_uuid == "hash_ek": ek_pubkey = pubkey_from_tpm2b_public(base64.b64decode(ek_tpm)) ek_pubkey_pem = ek_pubkey.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) agent_uuid = hashlib.sha256(ek_pubkey_pem).hexdigest() elif agent_uuid == "generate" or agent_uuid is None: agent_uuid = str(uuid.uuid4()) elif agent_uuid == "dmidecode": cmd = ["dmidecode", "-s", "system-uuid"] ret = cmd_exec.run(cmd) sys_uuid = ret["retout"][0].decode("utf-8") agent_uuid = sys_uuid.strip() try: uuid.UUID(agent_uuid) except ValueError as e: raise RuntimeError( # pylint: disable=raise-missing-from f"The UUID returned from dmidecode is invalid: {str(e)}") elif agent_uuid == "hostname": agent_uuid = socket.getfqdn() elif agent_uuid == "environment": agent_uuid = os.getenv("KEYLIME_AGENT_UUID", None) if agent_uuid is None: raise RuntimeError( "Env variable KEYLIME_AGENT_UUID is empty, but agent_uuid is set to 'environment'" ) elif not validators.valid_uuid(agent_uuid): raise RuntimeError("The UUID is not valid") if not validators.valid_agent_id(agent_uuid): raise RuntimeError( "The agent ID set via agent uuid parameter use invalid characters") logger.info("Agent UUID: %s", agent_uuid) serveraddr = (config.get("cloud_agent", "cloudagent_ip"), config.getint("cloud_agent", "cloudagent_port")) keylime_ca = config.get("cloud_agent", "keylime_ca") if keylime_ca == "default": keylime_ca = os.path.join(config.WORK_DIR, "cv_ca", "cacert.crt") server = CloudAgentHTTPServer(serveraddr, Handler, agent_uuid, contact_ip, ima_log_file, tpm_log_file_data) if server.mtls_cert_enabled: context = web_util.generate_mtls_context(server.mtls_cert_path, server.rsakey_path, keylime_ca, logger=logger) server.socket = context.wrap_socket(server.socket, server_side=True) else: if (not config.getboolean( "cloud_agent", "enable_insecure_payload", fallback=False) and config.get("cloud_agent", "payload_script") != ""): raise RuntimeError( "agent mTLS is disabled, while a tenant can instruct the agent to execute code on the node. " 'In order to allow the running of the agent, "enable_insecure_payload" has to be set to "True"' ) serverthread = threading.Thread(target=server.serve_forever, daemon=True) # register it and get back a blob mtls_cert = "disabled" if server.mtls_cert: mtls_cert = server.mtls_cert.public_bytes(serialization.Encoding.PEM) keyblob = registrar_client.doRegisterAgent(registrar_ip, registrar_port, agent_uuid, ek_tpm, ekcert, aik_tpm, mtls_cert, contact_ip, contact_port) if keyblob is None: instance_tpm.flush_keys() raise Exception("Registration failed") # get the ephemeral registrar key key = instance_tpm.activate_identity(keyblob) if key is None: instance_tpm.flush_keys() raise Exception("Activation failed") # tell the registrar server we know the key retval = registrar_client.doActivateAgent(registrar_ip, registrar_port, agent_uuid, key) if not retval: instance_tpm.flush_keys() raise Exception("Registration failed on activate") # Start revocation listener in a new process to not interfere with tornado revocation_process = multiprocessing.Process(target=revocation_listener, daemon=True) revocation_process.start() logger.info( "Starting Cloud Agent on %s:%s with API version %s. Use <Ctrl-C> to stop", serveraddr[0], serveraddr[1], keylime_api_version.current_version(), ) serverthread.start() def shutdown_handler(*_): logger.info("TERM Signal received, shutting down...") logger.debug("Stopping revocation notifier...") revocation_process.terminate() logger.debug("Shutting down HTTP server...") server.shutdown() server.server_close() serverthread.join() logger.debug("HTTP server stopped...") revocation_process.join() logger.debug("Revocation notifier stopped...") secure_mount.umount() logger.debug("Umounting directories...") instance_tpm.flush_keys() logger.debug("Flushed keys successfully") sys.exit(0) signal.signal(signal.SIGTERM, shutdown_handler) signal.signal(signal.SIGQUIT, shutdown_handler) signal.signal(signal.SIGINT, shutdown_handler) # Keep the main thread alive by waiting for the server thread serverthread.join()
def main(): for ML in [config.MEASUREDBOOT_ML, config.IMA_ML]: if not os.access(ML, os.F_OK): logger.warning( "Measurement list path %s not accessible by agent. Any attempt to instruct it to access this path - via \"keylime_tenant\" CLI - will result in agent process dying", ML) ima_log_file = None if os.path.exists(config.IMA_ML): ima_log_file = open(config.IMA_ML, 'r', encoding="utf-8") tpm_log_file_data = None if os.path.exists(config.MEASUREDBOOT_ML): with open(config.MEASUREDBOOT_ML, 'rb') as tpm_log_file: tpm_log_file_data = base64.b64encode(tpm_log_file.read()) if config.get('cloud_agent', 'agent_uuid') == 'dmidecode': if os.getuid() != 0: raise RuntimeError('agent_uuid is configured to use dmidecode, ' 'but current process is not running as root.') cmd = ['which', 'dmidecode'] ret = cmd_exec.run(cmd, raiseOnError=False) if ret['code'] != 0: raise RuntimeError('agent_uuid is configured to use dmidecode, ' 'but it\'s is not found on the system.') # initialize the tmpfs partition to store keys if it isn't already available secdir = secure_mount.mount() # Now that operations requiring root privileges are done, drop privileges # if 'run_as' is available in the configuration. if os.getuid() == 0: run_as = config.get('cloud_agent', 'run_as', fallback='') if run_as != '': user_utils.chown(secdir, run_as) user_utils.change_uidgid(run_as) logger.info(f"Dropped privileges to {run_as}") else: logger.warning( "Cannot drop privileges since 'run_as' is empty or missing in keylime.conf agent section." ) # Instanitate TPM class instance_tpm = tpm() # get params for initialization registrar_ip = config.get('cloud_agent', 'registrar_ip') registrar_port = config.get('cloud_agent', 'registrar_port') # get params for the verifier to contact the agent contact_ip = os.getenv("KEYLIME_AGENT_CONTACT_IP", None) if contact_ip is None and config.has_option('cloud_agent', 'agent_contact_ip'): contact_ip = config.get('cloud_agent', 'agent_contact_ip') contact_port = os.getenv("KEYLIME_AGENT_CONTACT_PORT", None) if contact_port is None and config.has_option('cloud_agent', 'agent_contact_port'): contact_port = config.get('cloud_agent', 'agent_contact_port', fallback="invalid") # change dir to working dir fs_util.ch_dir(config.WORK_DIR) # set a conservative general umask os.umask(0o077) # initialize tpm (ekcert, ek_tpm, aik_tpm) = instance_tpm.tpm_init( self_activate=False, config_pw=config.get('cloud_agent', 'tpm_ownerpassword') ) # this tells initialize not to self activate the AIK virtual_agent = instance_tpm.is_vtpm() # Warn if kernel version is <5.10 and another algorithm than SHA1 is used, # because otherwise IMA will not work kernel_version = tuple(platform.release().split("-")[0].split(".")) if tuple(map(int, kernel_version)) < ( 5, 10, 0) and instance_tpm.defaults["hash"] != algorithms.Hash.SHA1: logger.warning( "IMA attestation only works on kernel versions <5.10 with SHA1 as hash algorithm. " "Even if ascii_runtime_measurements shows \"%s\" as the " "algorithm, it might be just padding zeros", (instance_tpm.defaults["hash"])) if ekcert is None: if virtual_agent: ekcert = 'virtual' elif instance_tpm.is_emulator(): ekcert = 'emulator' # now we need the UUID try: agent_uuid = config.get('cloud_agent', 'agent_uuid') except configparser.NoOptionError: agent_uuid = None if agent_uuid == 'hash_ek': ek_pubkey = pubkey_from_tpm2b_public(base64.b64decode(ek_tpm)) ek_pubkey_pem = ek_pubkey.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) agent_uuid = hashlib.sha256(ek_pubkey_pem).hexdigest() elif agent_uuid == 'generate' or agent_uuid is None: agent_uuid = str(uuid.uuid4()) elif agent_uuid == 'dmidecode': cmd = ['dmidecode', '-s', 'system-uuid'] ret = cmd_exec.run(cmd) sys_uuid = ret['retout'][0].decode('utf-8') agent_uuid = sys_uuid.strip() try: uuid.UUID(agent_uuid) except ValueError as e: raise RuntimeError( "The UUID returned from dmidecode is invalid: %s" % e) # pylint: disable=raise-missing-from elif agent_uuid == 'hostname': agent_uuid = socket.getfqdn() elif agent_uuid == 'environment': agent_uuid = os.getenv("KEYLIME_AGENT_UUID", None) if agent_uuid is None: raise RuntimeError( "Env variable KEYLIME_AGENT_UUID is empty, but agent_uuid is set to 'environment'" ) elif not validators.valid_uuid(agent_uuid): raise RuntimeError("The UUID is not valid") if not validators.valid_agent_id(agent_uuid): raise RuntimeError( "The agent ID set via agent uuid parameter use invalid characters") if config.STUB_VTPM and config.TPM_CANNED_VALUES is not None: # Use canned values for stubbing jsonIn = config.TPM_CANNED_VALUES if "add_vtpm_to_group" in jsonIn: # The value we're looking for has been canned! agent_uuid = jsonIn['add_vtpm_to_group']['retout'] else: # Our command hasn't been canned! raise Exception("Command %s not found in canned json!" % ("add_vtpm_to_group")) logger.info("Agent UUID: %s", agent_uuid) serveraddr = (config.get('cloud_agent', 'cloudagent_ip'), config.getint('cloud_agent', 'cloudagent_port')) keylime_ca = config.get('cloud_agent', 'keylime_ca') if keylime_ca == "default": keylime_ca = os.path.join(config.WORK_DIR, 'cv_ca', 'cacert.crt') server = CloudAgentHTTPServer(serveraddr, Handler, agent_uuid, contact_ip, ima_log_file, tpm_log_file_data) context = web_util.generate_mtls_context(server.mtls_cert_path, server.rsakey_path, keylime_ca, logger=logger) server.socket = context.wrap_socket(server.socket, server_side=True) serverthread = threading.Thread(target=server.serve_forever, daemon=True) # register it and get back a blob mtls_cert = server.mtls_cert.public_bytes(serialization.Encoding.PEM) keyblob = registrar_client.doRegisterAgent(registrar_ip, registrar_port, agent_uuid, ek_tpm, ekcert, aik_tpm, mtls_cert, contact_ip, contact_port) if keyblob is None: instance_tpm.flush_keys() raise Exception("Registration failed") # get the ephemeral registrar key key = instance_tpm.activate_identity(keyblob) if key is None: instance_tpm.flush_keys() raise Exception("Activation failed") # tell the registrar server we know the key retval = registrar_client.doActivateAgent(registrar_ip, registrar_port, agent_uuid, key) if not retval: instance_tpm.flush_keys() raise Exception("Registration failed on activate") # Start revocation listener in a new process to not interfere with tornado revocation_process = multiprocessing.Process(target=revocation_listener, daemon=True) revocation_process.start() logger.info( "Starting Cloud Agent on %s:%s with API version %s. Use <Ctrl-C> to stop", serveraddr[0], serveraddr[1], keylime_api_version.current_version()) serverthread.start() def shutdown_handler(*_): logger.info("TERM Signal received, shutting down...") logger.debug("Stopping revocation notifier...") revocation_process.terminate() logger.debug("Shutting down HTTP server...") server.shutdown() server.server_close() serverthread.join() logger.debug("HTTP server stopped...") revocation_process.join() logger.debug("Revocation notifier stopped...") secure_mount.umount() logger.debug("Umounting directories...") instance_tpm.flush_keys() logger.debug("Flushed keys successfully") sys.exit(0) signal.signal(signal.SIGTERM, shutdown_handler) signal.signal(signal.SIGQUIT, shutdown_handler) signal.signal(signal.SIGINT, shutdown_handler) # Keep the main thread alive by waiting for the server thread serverthread.join()