def remove_xcluster_root_cert(self, ssh_options, replication_config_name, producer_certs_dir): def check_rm_result(rm_result): if rm_result.exited and rm_result.stderr.find( "No such file or directory") == -1: raise YBOpsRuntimeError( "Remote shell command 'rm' failed with " "return code '{}' and error '{}'".format( rm_result.stderr.encode('utf-8'), rm_result.exited)) if producer_certs_dir is None: producer_certs_dir = self.PRODUCER_CERTS_DIR_NAME remote_shell = RemoteShell(ssh_options) node_ip = ssh_options["ssh_host"] src_root_cert_dir_path = os.path.join(producer_certs_dir, replication_config_name) src_root_cert_path = os.path.join(src_root_cert_dir_path, self.ROOT_CERT_NAME) logging.info( "Removing server cert located at {} from server {}.".format( src_root_cert_dir_path, node_ip)) remote_shell.run_command( 'chmod -f 666 {}/* || true'.format(src_root_cert_dir_path)) result = remote_shell.run_command_raw('rm ' + src_root_cert_path) check_rm_result(result) # Remove the directory only if it is empty. result = remote_shell.run_command_raw('rm -d ' + src_root_cert_dir_path) check_rm_result(result) # No need to check the result of this command. remote_shell.run_command_raw('rm -d ' + producer_certs_dir)
def verify_certs(self, root_crt_path, node_crt_path, ssh_options, verify_hostname=False): remote_shell = RemoteShell(ssh_options) try: remote_shell.run_command('which openssl') except YBOpsRuntimeError: logging.debug( "Openssl not found, skipping certificate verification.") return # Verify if the node cert is not expired validity_verify = remote_shell.run_command_raw( "openssl x509 -noout -checkend 86400 -in {}".format(node_crt_path)) if validity_verify.exited == 1: raise YBOpsRuntimeError( "Node cert: {} is expired or will expire in one day.".format( node_crt_path)) # Verify if node cert has valid signature signature_verify = remote_shell.run_command_raw( "openssl verify -CAfile {} {} | egrep error".format( root_crt_path, node_crt_path)) if signature_verify.exited != 1: raise YBOpsRuntimeError( "Node cert: {} is not signed by the provided root cert: {}.". format(node_crt_path, root_crt_path)) if verify_hostname: self.__verify_certs_hostname(node_crt_path, ssh_options)
def verify_certs(self, root_crt_path, node_crt_path, ssh_options, verify_hostname=False): remote_shell = RemoteShell(ssh_options) # Verify that both cert are present in FS and have read rights root_file_verify = remote_shell.run_command_raw( "test -r {}".format(root_crt_path)) if root_file_verify.exited == 1: raise YBOpsRuntimeError( "Root cert: {} is absent or is not readable.".format( root_crt_path)) node_file_verify = remote_shell.run_command_raw( "test -r {}".format(node_crt_path)) if node_file_verify.exited == 1: raise YBOpsRuntimeError( "Node cert: {} is absent or is not readable.".format( node_crt_path)) try: remote_shell.run_command('which openssl') except YBOpsRuntimeError: logging.debug( "Openssl not found, skipping certificate verification.") return # Verify if root and node certs are valid cert_verify = remote_shell.run_command_raw( ("openssl crl2pkcs7 -nocrl -certfile {} -certfile {} " "| openssl pkcs7 -print_certs -text -noout").format( root_crt_path, node_crt_path)) if cert_verify.exited == 1: raise YBOpsRuntimeError( "Provided certs ({}, {}) are not valid.".format( root_crt_path, node_crt_path)) # Verify if the node cert is not expired validity_verify = remote_shell.run_command_raw( "openssl x509 -noout -checkend 86400 -in {}".format(node_crt_path)) if validity_verify.exited == 1: raise YBOpsRuntimeError( "Node cert: {} is expired or will expire in one day.".format( node_crt_path)) # Verify if node cert has valid signature signature_verify = remote_shell.run_command_raw( "openssl verify -CAfile {} {} | egrep error".format( root_crt_path, node_crt_path)) if signature_verify.exited != 1: raise YBOpsRuntimeError( "Node cert: {} is not signed by the provided root cert: {}.". format(node_crt_path, root_crt_path)) if verify_hostname: self.__verify_certs_hostname(node_crt_path, ssh_options)
def remove_old_root_cert(self, ssh_options, certs_dir): remote_shell = RemoteShell(ssh_options) yb_root_cert_path = os.path.join(certs_dir, self.ROOT_CERT_NAME) yb_root_cert_new_path = os.path.join(certs_dir, self.ROOT_CERT_NEW_NAME) # Check if ca_new.crt is present, it will be present if # APPEND_NEW_ROOT_CERT action was performed before file_verify = remote_shell.run_command_raw( "test -f '{}'".format(yb_root_cert_new_path)) # No action needed if ca_new.crt is not present if not file_verify.exited: # Give write permissions to cert directory remote_shell.run_command( 'chmod -f 666 {}/* || true'.format(certs_dir)) # Remove ca.crt and rename ca_new.crt to ca.crt remote_shell.run_command("mv '{}' '{}'".format( yb_root_cert_new_path, yb_root_cert_path)) # Reset the write permissions remote_shell.run_command('chmod 400 {}/*'.format(certs_dir))
def copy_server_certs(self, ssh_options, root_cert_path, server_cert_path, server_key_path, certs_location, certs_dir, rotate_certs, skip_cert_validation): remote_shell = RemoteShell(ssh_options) node_ip = ssh_options["ssh_host"] cert_file = 'node.{}.crt'.format(node_ip) key_file = 'node.{}.key'.format(node_ip) yb_root_cert_path = os.path.join(certs_dir, self.ROOT_CERT_NAME) yb_server_cert_path = os.path.join(certs_dir, cert_file) yb_server_key_path = os.path.join(certs_dir, key_file) copy_root = True if rotate_certs: root_cert_command = remote_shell.run_command_raw( "cat '{}'".format(yb_root_cert_path)) # In case of tls toggle root cert might not be present if not root_cert_command.exited: root_cert = root_cert_command.stdout root_cert_new = None if certs_location == self.CERT_LOCATION_NODE: root_cert_new = remote_shell.run_command( "cat '{}'".format(root_cert_path)).stdout if certs_location == self.CERT_LOCATION_PLATFORM: with open(root_cert_path) as file: root_cert_new = file.read() if root_cert is not None and root_cert_new is not None: compare_result = self.compare_certs( root_cert_new, root_cert) if compare_result == 0 or compare_result == 1: # Don't copy root certs if the new root cert is # same or subset of the existing root cert copy_root = False else: raise YBOpsRuntimeError( "Unable to fetch the certificate {}".format( root_cert_path)) logging.info("Moving server certs located at {}, {}, {}.".format( root_cert_path, server_cert_path, server_key_path)) remote_shell.run_command('mkdir -p ' + certs_dir) # Give write permissions. If the command fails, ignore. remote_shell.run_command('chmod -f 666 {}/* || true'.format(certs_dir)) if certs_location == self.CERT_LOCATION_NODE: if skip_cert_validation == 'ALL': logging.info( "Skipping all validations for certs for node {}".format( node_ip)) else: verify_hostname = True if skip_cert_validation == 'HOSTNAME': logging.info( "Skipping host name validation for certs for node {}". format(node_ip)) verify_hostname = False self.verify_certs(root_cert_path, server_cert_path, ssh_options, verify_hostname) if copy_root: remote_shell.run_command("cp '{}' '{}'".format( root_cert_path, yb_root_cert_path)) remote_shell.run_command("cp '{}' '{}'".format( server_cert_path, yb_server_cert_path)) remote_shell.run_command("cp '{}' '{}'".format( server_key_path, yb_server_key_path)) if certs_location == self.CERT_LOCATION_PLATFORM: if copy_root: remote_shell.put_file(root_cert_path, yb_root_cert_path) remote_shell.put_file(server_cert_path, yb_server_cert_path) remote_shell.put_file(server_key_path, yb_server_key_path) # Reset the write permission as a sanity check. remote_shell.run_command('chmod 400 {}/*'.format(certs_dir))