def start_daemon(): args = [os.path.join(os.getcwd(), __file__), "-daemon"] logger.log("start_daemon with args:" + str(args)) #This process will start a new background process by calling # handle.py -daemon #to run the script and will exit itself immediatelly. #Redirect stdout and stderr to /dev/null. Otherwise daemon process will #throw Broke pipe exeception when parent process exit. devnull = open(os.devnull, 'w') child = subprocess.Popen(args, stdout=devnull, stderr=devnull) encryption_config = EncryptionConfig(encryption_environment,logger) if(encryption_config.config_file_exists()): hutil.do_exit(exit_code = 0, operation = 'Enable', status = CommonVariables.extension_success_status, code = str(CommonVariables.success), message = encryption_config.get_secret_id()) else: hutil.do_exit(exit_code = 0, operation = 'Enable', status = CommonVariables.extension_error_status, code = str(CommonVariables.encryption_failed), message = 'encryption config not found.')
def __init__(self, state_name, context): super(OSEncryptionState, self).__init__() self.state_name = state_name self.context = context self.state_executed = False self.state_marker = os.path.join( self.context.encryption_environment.os_encryption_markers_path, self.state_name) self.command_executor = CommandExecutor(self.context.logger) self.disk_util = DiskUtil( hutil=self.context.hutil, patching=self.context.distro_patcher, logger=self.context.logger, encryption_environment=self.context.encryption_environment) self.bek_util = BekUtil(disk_util=self.disk_util, logger=self.context.logger) self.encryption_config = EncryptionConfig( encryption_environment=self.context.encryption_environment, logger=self.context.logger) rootfs_mountpoint = '/' if self.command_executor.Execute('mountpoint /oldroot') == 0: rootfs_mountpoint = '/oldroot' rootfs_sdx_path = self._get_fs_partition(rootfs_mountpoint)[0] self.context.logger.log("rootfs_sdx_path: {0}".format(rootfs_sdx_path)) self.rootfs_block_device = self.disk_util.query_dev_id_path_by_sdx_path( rootfs_sdx_path) if not self.rootfs_block_device.startswith('/dev'): distro_name = self.context.distro_patcher.distro_info[0] self.rootfs_block_device = '/dev/sda1' if distro_name == 'Ubuntu' else '/dev/sda2' self.context.logger.log("rootfs_block_device: {0}".format( self.rootfs_block_device))
def __init__(self, state_name, context): super(OSEncryptionState, self).__init__() self.state_name = state_name self.context = context self.state_executed = False self.state_marker = os.path.join( self.context.encryption_environment.os_encryption_markers_path, self.state_name) self.command_executor = CommandExecutor(self.context.logger) self.disk_util = DiskUtil( hutil=self.context.hutil, patching=self.context.distro_patcher, logger=self.context.logger, encryption_environment=self.context.encryption_environment) self.bek_util = BekUtil(disk_util=self.disk_util, logger=self.context.logger) self.encryption_config = EncryptionConfig( encryption_environment=self.context.encryption_environment, logger=self.context.logger) rootfs_mountpoint = '/' if self._is_in_memfs_root(): rootfs_mountpoint = '/oldroot' self.rootfs_sdx_path = self._get_fs_partition(rootfs_mountpoint)[0] if self.rootfs_sdx_path == "none": self.context.logger.log( "self.rootfs_sdx_path is none, parsing UUID from fstab") self.rootfs_sdx_path = self._parse_uuid_from_fstab('/') self.context.logger.log("rootfs_uuid: {0}".format( self.rootfs_sdx_path)) if self.rootfs_sdx_path and ( self.rootfs_sdx_path.startswith("/dev/disk/by-uuid/") or self._is_uuid(self.rootfs_sdx_path)): self.rootfs_sdx_path = self.disk_util.query_dev_sdx_path_by_uuid( self.rootfs_sdx_path) self.context.logger.log("self.rootfs_sdx_path: {0}".format( self.rootfs_sdx_path)) self.rootfs_disk = None self.rootfs_block_device = None self.bootfs_block_device = None if self.disk_util.is_os_disk_lvm(): proc_comm = ProcessCommunicator() self.command_executor.Execute('pvs', True, communicator=proc_comm) for line in proc_comm.stdout.split("\n"): if "rootvg" in line: self.rootfs_block_device = line.strip().split()[0] self.rootfs_disk = self.rootfs_block_device[:-1] self.bootfs_block_device = self.rootfs_disk + '2' elif not self.rootfs_sdx_path: self.rootfs_disk = '/dev/sda' self.rootfs_block_device = '/dev/sda2' self.bootfs_block_device = '/dev/sda1' elif self.rootfs_sdx_path == '/dev/mapper/osencrypt' or self.rootfs_sdx_path.startswith( '/dev/dm-'): self.rootfs_block_device = '/dev/mapper/osencrypt' bootfs_uuid = self._parse_uuid_from_fstab('/boot') self.context.logger.log("bootfs_uuid: {0}".format(bootfs_uuid)) self.bootfs_block_device = self.disk_util.query_dev_sdx_path_by_uuid( bootfs_uuid) else: self.rootfs_block_device = self.disk_util.query_dev_id_path_by_sdx_path( self.rootfs_sdx_path) if not self.rootfs_block_device.startswith('/dev/disk/by-id/'): self.context.logger.log("rootfs_block_device: {0}".format( self.rootfs_block_device)) raise Exception("Could not find rootfs block device") self.rootfs_disk = self.rootfs_block_device[:self. rootfs_block_device. index("-part")] self.bootfs_block_device = self.rootfs_disk + "-part2" if self._get_block_device_size( self.bootfs_block_device) > self._get_block_device_size( self.rootfs_block_device): self.context.logger.log( "Swapping partition identifiers for rootfs and bootfs") self.rootfs_block_device, self.bootfs_block_device = self.bootfs_block_device, self.rootfs_block_device self.context.logger.log("rootfs_disk: {0}".format(self.rootfs_disk)) self.context.logger.log("rootfs_block_device: {0}".format( self.rootfs_block_device)) self.context.logger.log("bootfs_block_device: {0}".format( self.bootfs_block_device))
def daemon(): hutil.do_parse_context('Executing') try: # Ensure the same configuration is executed only once # If the previous enable failed, we do not have retry logic here. # TODO Remount all encryption_marker = EncryptionMarkConfig(logger, encryption_environment) if(encryption_marker.config_file_exists()): logger.log("encryption is marked.") """ search for the bek volume, then mount it:) """ disk_util = DiskUtil(hutil, MyPatching, logger, encryption_environment) encryption_config = EncryptionConfig(encryption_environment,logger) bek_passphrase_file = None """ try to find the attached bek volume, and use the file to mount the crypted volumes, and if the passphrase file is found, then we will re-use it for the future. """ bek_util = BekUtil(disk_util, logger) if(encryption_config.config_file_exists()): bek_passphrase_file = bek_util.get_bek_passphrase_file(encryption_config) if(bek_passphrase_file is None): hutil.do_exit(0, 'Enable', CommonVariables.extension_error_status, CommonVariables.passphrase_file_not_found, 'Passphrase file not found.') else: """ check whether there's a scheduled encryption task """ logger.log("trying to install the extras") MyPatching.install_extras() mount_all_result = disk_util.mount_all() if(mount_all_result != CommonVariables.process_success): logger.log(msg=("mount all failed with code " + str(mount_all_result)), level=CommonVariables.ErrorLevel) """ TODO: resuming the encryption for rebooting suddenly scenario we need the special handling is because the half done device can be a error state: say, the file system header missing.so it could be identified. """ ongoing_item_config = OnGoingItemConfig(encryption_environment=encryption_environment, logger=logger) if(ongoing_item_config.config_file_exists()): header_file_path = ongoing_item_config.get_header_file_path() mount_point = ongoing_item_config.get_mount_point() if(not none_or_empty(mount_point)): logger.log("mount point is not empty, trying to unmount it first." + str(mount_point)) umount_status_code = disk_util.umount(mount_point) logger.log("unmount return code is " + str(umount_status_code)) if(none_or_empty(header_file_path)): encryption_result_phase = encrypt_inplace_without_seperate_header_file(passphrase_file = bek_passphrase_file, device_item = None,\ disk_util = disk_util, bek_util = bek_util, ongoing_item_config = ongoing_item_config) else: encryption_result_phase = encrypt_inplace_with_seperate_header_file(passphrase_file = bek_passphrase_file, device_item = None,\ disk_util = disk_util, bek_util = bek_util, ongoing_item_config = ongoing_item_config) """ if the resuming failed, we should fail. """ if(encryption_result_phase != CommonVariables.EncryptionPhaseDone): hutil.do_exit(exit_code = 0, operation = 'Enable', status = CommonVariables.extension_error_status, code = CommonVariables.encryption_failed,\ message = 'resuming encryption for ' + str(ongoing_item_config.original_dev_path) + ' failed.') else: ongoing_item_config.clear_config() else: failed_item = None if(encryption_marker.get_current_command() == CommonVariables.EnableEncryption): failed_item = enable_encryption_all_in_place(passphrase_file= bek_passphrase_file, encryption_marker = encryption_marker, disk_util = disk_util, bek_util = bek_util) elif(encryption_marker.get_current_command() == CommonVariables.EnableEncryptionFormat): failed_item = enable_encryption_format(passphrase = bek_passphrase_file, encryption_marker = encryption_marker, disk_util = disk_util) else: logger.log(msg = ("command " + str(encryption_marker.get_current_command()) + " not supported"), level = CommonVariables.ErrorLevel) #TODO do exit here if(failed_item != None): hutil.do_exit(exit_code = 0, operation = 'Enable', status = CommonVariables.extension_error_status, code = CommonVariables.encryption_failed,\ message = 'encryption failed for ' + str(failed_item)) else: hutil.do_exit(exit_code = 0, operation = 'Enable', status = CommonVariables.extension_success_status, code = str(CommonVariables.success), message = encryption_config.get_secret_id()) except Exception as e: # mount the file systems back. error_msg = ("Failed to enable the extension with error: %s, stack trace: %s" % (str(e), traceback.format_exc())) logger.log(msg = error_msg, level = CommonVariables.ErrorLevel) hutil.do_exit(exit_code = 0, operation = 'Enable', status = CommonVariables.extension_error_status, code = str(CommonVariables.encryption_failed), \ message = error_msg) finally: encryption_marker = EncryptionMarkConfig(logger, encryption_environment) #TODO not remove it, backed it up. logger.log("clearing the encryption mark.") encryption_marker.clear_config() bek_util.umount_azure_passhprase(encryption_config) logger.log("finally in daemon")
def enable(): hutil.do_parse_context('Enable') # we need to start another subprocess to do it, because the initial process # would be killed by the wala in 5 minutes. logger.log('enabling...') """ trying to mount the crypted items. """ disk_util = DiskUtil(hutil = hutil, patching = MyPatching, logger = logger, encryption_environment = encryption_environment) bek_util = BekUtil(disk_util, logger) existed_passphrase_file = None encryption_config = EncryptionConfig(encryption_environment=encryption_environment, logger = logger) config_path_result = disk_util.make_sure_path_exists(encryption_environment.encryption_config_path) if(config_path_result != CommonVariables.process_success): logger.log(msg="azure encryption path creation failed.",level=CommonVariables.ErrorLevel) if(encryption_config.config_file_exists()): existed_passphrase_file = bek_util.get_bek_passphrase_file(encryption_config) if(existed_passphrase_file is not None): mount_encrypted_disks(disk_util=disk_util,bek_util=bek_util,encryption_config=encryption_config,passphrase_file=existed_passphrase_file) else: logger.log(msg="the config is there, but we could not get the bek file.",level=CommonVariables.WarningLevel) exit_without_status_report() # handle the re-call scenario. the re-call would resume? # if there's one tag for the next reboot. encryption_marker = EncryptionMarkConfig(logger, encryption_environment) if (not encryption_marker.config_file_exists()): machine_identity = MachineIdentity() stored_identity = machine_identity.stored_identity() if(stored_identity is None): machine_identity.save_identity() else: current_identity = machine_identity.current_identity() if(current_identity != stored_identity): current_seq_no = -1 backup_logger.log("machine identity not same, set current_seq_no to " + str(current_seq_no) + " " + str(stored_identity) + " " + str(current_identity), True) hutil.set_last_seq(current_seq_no) machine_identity.save_identity() # we should be careful about proceed for this case, we just # failed this time to wait for customers' retry. exit_without_status_report() hutil.exit_if_same_seq() hutil.save_seq() try: protected_settings_str = hutil._context._config['runtimeSettings'][0]['handlerSettings'].get('protectedSettings') public_settings_str = hutil._context._config['runtimeSettings'][0]['handlerSettings'].get('publicSettings') if(isinstance(public_settings_str,basestring)): public_settings = json.loads(public_settings_str) else: public_settings = public_settings_str; if(isinstance(protected_settings_str,basestring)): protected_settings = json.loads(protected_settings_str) else: protected_settings = protected_settings_str extension_parameter = ExtensionParameter(hutil, protected_settings, public_settings) kek_secret_id_created = None encryption_marker = EncryptionMarkConfig(logger, encryption_environment) if encryption_marker.config_file_exists(): # verify the encryption mark logger.log(msg="encryption mark is there, starting daemon.",level=CommonVariables.InfoLevel) start_daemon() else: if(encryption_config.config_file_exists() and existed_passphrase_file is not None): logger.log(msg="config file exists and passphrase file exists.", level=CommonVariables.WarningLevel) encryption_marker = mark_encryption(command=extension_parameter.command, \ volume_type=extension_parameter.VolumeType, \ disk_format_query=extension_parameter.DiskFormatQuery) start_daemon() else: """ creating the secret, the secret would be transferred to a bek volume after the updatevm called in powershell. """ #store the luks passphrase in the secret. keyVaultUtil = KeyVaultUtil(logger) """ validate the parameters """ if(extension_parameter.VolumeType != 'Data'): hutil.do_exit(0, 'Enable', CommonVariables.extension_error_status,str(CommonVariables.volue_type_not_support), 'VolumeType ' + str(extension_parameter.VolumeType) + ' is not supported.') if(extension_parameter.command not in [CommonVariables.EnableEncryption, CommonVariables.EnableEncryptionFormat]): hutil.do_exit(0, 'Enable', CommonVariables.extension_error_status,str(CommonVariables.command_not_support), 'Command ' + str(extension_parameter.command) + ' is not supported.') """ this is the fresh call case """ #handle the passphrase related if(existed_passphrase_file is None): if(extension_parameter.passphrase is None or extension_parameter.passphrase == ""): extension_parameter.passphrase = bek_util.generate_passphrase(extension_parameter.KeyEncryptionAlgorithm) else: logger.log(msg="the extension_parameter.passphrase is none") kek_secret_id_created = keyVaultUtil.create_kek_secret(Passphrase = extension_parameter.passphrase,\ KeyVaultURL = extension_parameter.KeyVaultURL,\ KeyEncryptionKeyURL = extension_parameter.KeyEncryptionKeyURL,\ AADClientID = extension_parameter.AADClientID,\ KeyEncryptionAlgorithm = extension_parameter.KeyEncryptionAlgorithm,\ AADClientSecret = extension_parameter.AADClientSecret,\ DiskEncryptionKeyFileName = extension_parameter.DiskEncryptionKeyFileName) if(kek_secret_id_created is None): hutil.do_exit(0, 'Enable', CommonVariables.extension_error_status, str(CommonVariables.create_encryption_secret_failed), 'Enable failed.') else: encryption_config.passphrase_file_name = extension_parameter.DiskEncryptionKeyFileName encryption_config.bek_filesystem = CommonVariables.BekVolumeFileSystem encryption_config.secret_id = kek_secret_id_created encryption_config.commit() encryption_marker = mark_encryption(command=extension_parameter.command, \ volume_type=extension_parameter.VolumeType, \ disk_format_query=extension_parameter.DiskFormatQuery) if(kek_secret_id_created != None): hutil.do_exit(0, 'Enable', CommonVariables.extension_success_status, str(CommonVariables.success), str(kek_secret_id_created)) else: """ the enabling called again. the passphrase would be re-used. """ hutil.do_exit(0, 'Enable', CommonVariables.extension_success_status, str(CommonVariables.encrypttion_already_enabled), str(kek_secret_id_created)) except Exception as e: logger.log(msg="Failed to enable the extension with error: %s, stack trace: %s" % (str(e), traceback.format_exc()),level=CommonVariables.ErrorLevel) hutil.do_exit(0, 'Enable',CommonVariables.extension_error_status,str(CommonVariables.unknown_error), 'Enable failed.')