def __init__(self,patching,logger): self.mounts = [] disk_util = DiskUtil(patching,logger) device_items = disk_util.get_device_items(None); for device_item in device_items: mount = Mount(device_item.name, device_item.type, device_item.file_system, device_item.mount_point) self.mounts.append(mount)
def __init__(self, hutil, logger, distro_patcher): self.hutil = hutil self.logger = logger self.executor = CommandExecutor(self.logger) self.disk_util = DiskUtil(hutil=self.hutil, patching=distro_patcher, logger=self.logger, encryption_environment=None) self.mapper_name = str(uuid.uuid4()) self.mapper_path = self.DM_PREFIX + self.mapper_name
def get_loop_devices(self): disk_util = DiskUtil(patching=self.patching, logger=self.logger) if len(self.file_systems_info) == 0: self.file_systems_info = disk_util.get_mount_file_systems() self.logger.log("file_systems list : ", True) self.logger.log(str(self.file_systems_info), True) disk_loop_devices_file_systems = [] for file_system_info in self.file_systems_info: if 'loop' in file_system_info[0]: disk_loop_devices_file_systems.append(file_system_info[0]) return disk_loop_devices_file_systems
def get_loop_devices(self): disk_util = DiskUtil(patching = self.patching,logger = self.logger) if len(self.file_systems_info) == 0 : self.file_systems_info = disk_util.get_mount_file_systems() self.logger.log("file_systems list : ",True) self.logger.log(str(self.file_systems_info),True) disk_loop_devices_file_systems = [] for file_system_info in self.file_systems_info: if 'loop' in file_system_info[0]: disk_loop_devices_file_systems.append(file_system_info[0]) return disk_loop_devices_file_systems
def __init__(self, patching, logger): self.mounts = [] added_mount_point_names = [] disk_util = DiskUtil(patching, logger) # Get mount points mount_points, fs_types = disk_util.get_mount_points(None) # Get lsblk devices device_items = disk_util.get_device_items(None) lsblk_mounts = [] lsblk_mount_points = [] lsblk_fs_types = [] # List to hold mount-points returned from lsblk command but not reurned from mount command lsblk_mounts_not_in_mount = [] for device_item in device_items: mount = Mount(device_item.name, device_item.type, device_item.file_system, device_item.mount_point) lsblk_mounts.append(mount) logger.log( "lsblk mount point " + str(device_item.mount_point) + " added with fs type " + str(device_item.file_system), True) lsblk_mount_points.append(device_item.mount_point) lsblk_fs_types.append(device_item.file_system) # If lsblk mount is not found in "mount command" mount-list, add it to the lsblk_mounts_not_in_mount array if ((device_item.mount_point not in mount_points) and (device_item.mount_point not in lsblk_mounts_not_in_mount)): lsblk_mounts_not_in_mount.append(device_item.mount_point) # Sort lsblk_mounts_not_in_mount array in ascending order lsblk_mounts_not_in_mount.sort() # Add the lsblk devices in the same order as they are returned in mount command output for mount_point, fs_type in zip(mount_points, fs_types): if ((mount_point in lsblk_mount_points) and (mount_point not in added_mount_point_names)): mountObj = lsblk_mounts[lsblk_mount_points.index(mount_point)] if (mountObj.fstype is None or mountObj.fstype == "" or mountObj.fstype == " "): logger.log( "fstype empty from lsblk for mount" + str(mount_point), True) mountObj.fstype = fs_type self.mounts.append(mountObj) added_mount_point_names.append(mount_point) # Append all the lsblk devices corresponding to lsblk_mounts_not_in_mount list mount-points for mount_point in lsblk_mounts_not_in_mount: if ((mount_point in lsblk_mount_points) and (mount_point not in added_mount_point_names)): self.mounts.append( lsblk_mounts[lsblk_mount_points.index(mount_point)]) added_mount_point_names.append(mount_point) added_mount_point_names.reverse() logger.log("added_mount_point_names :" + str(added_mount_point_names), True) # Reverse the mounts list self.mounts.reverse()
def __init__(self, hutil, logger, distro_patcher, encryption_environment, protected_settings, public_settings): """ TODO: we should validate the parameter first """ self.hutil = hutil self.logger = logger self.distro_patcher = distro_patcher self.encryption_environment = encryption_environment self.disk_util = DiskUtil( hutil=hutil, patching=distro_patcher, logger=logger, encryption_environment=encryption_environment) self.bek_util = BekUtil(self.disk_util, logger) self.encryption_config = EncryptionConfig(encryption_environment, logger) self.command = public_settings.get( CommonVariables.EncryptionEncryptionOperationKey) self.KeyEncryptionKeyURL = public_settings.get( CommonVariables.KeyEncryptionKeyURLKey) self.KeyVaultURL = public_settings.get(CommonVariables.KeyVaultURLKey) self.AADClientID = public_settings.get(CommonVariables.AADClientIDKey) self.AADClientCertThumbprint = public_settings.get( CommonVariables.AADClientCertThumbprintKey) keyEncryptionAlgorithm = public_settings.get( CommonVariables.KeyEncryptionAlgorithmKey) if keyEncryptionAlgorithm is not None and keyEncryptionAlgorithm != "": self.KeyEncryptionAlgorithm = keyEncryptionAlgorithm else: self.KeyEncryptionAlgorithm = 'RSA-OAEP' self.VolumeType = public_settings.get(CommonVariables.VolumeTypeKey) self.DiskFormatQuery = public_settings.get( CommonVariables.DiskFormatQuerykey) """ private settings """ self.AADClientSecret = protected_settings.get( CommonVariables.AADClientSecretKey) if self.AADClientSecret is None: self.AADClientSecret = '' self.passphrase = protected_settings.get(CommonVariables.PassphraseKey) self.DiskEncryptionKeyFileName = "LinuxPassPhraseFileName" # parse the query from the array self.params_config = ConfigUtil( encryption_environment.extension_parameter_file_path, 'azure_extension_params', logger)
def __init__(self,patching,logger): self.mounts = [] added_mount_point_names = [] disk_util = DiskUtil(patching,logger) # Get mount points mount_points, fs_types = disk_util.get_mount_points() # Get lsblk devices device_items = disk_util.get_device_items(None); lsblk_mounts = [] lsblk_mount_points = [] lsblk_fs_types = [] # List to hold mount-points returned from lsblk command but not reurned from mount command lsblk_mounts_not_in_mount = [] for device_item in device_items: mount = Mount(device_item.name, device_item.type, device_item.file_system, device_item.mount_point) lsblk_mounts.append(mount) logger.log("lsblk mount point "+str(device_item.mount_point)+" added with fs type "+str(device_item.file_system), True) lsblk_mount_points.append(device_item.mount_point) lsblk_fs_types.append(device_item.file_system) # If lsblk mount is not found in "mount command" mount-list, add it to the lsblk_mounts_not_in_mount array if((device_item.mount_point not in mount_points) and (device_item.mount_point not in lsblk_mounts_not_in_mount)): lsblk_mounts_not_in_mount.append(device_item.mount_point) # Sort lsblk_mounts_not_in_mount array in ascending order lsblk_mounts_not_in_mount.sort() # Add the lsblk devices in the same order as they are returned in mount command output for mount_point, fs_type in zip(mount_points, fs_types): if((mount_point in lsblk_mount_points) and (mount_point not in added_mount_point_names)): mountObj = lsblk_mounts[lsblk_mount_points.index(mount_point)] if(mountObj.fstype is None or mountObj.fstype == "" or mountObj.fstype == " "): logger.log("fstype empty from lsblk for mount" + str(mount_point), True) mountObj.fstype = fs_type self.mounts.append(mountObj) added_mount_point_names.append(mount_point) # Append all the lsblk devices corresponding to lsblk_mounts_not_in_mount list mount-points for mount_point in lsblk_mounts_not_in_mount: if((mount_point in lsblk_mount_points) and (mount_point not in added_mount_point_names)): self.mounts.append(lsblk_mounts[lsblk_mount_points.index(mount_point)]) added_mount_point_names.append(mount_point) added_mount_point_names.reverse() logger.log("added_mount_point_names :" + str(added_mount_point_names), True) # Reverse the mounts list self.mounts.reverse()
class ResourceDiskUtil(object): """ Resource Disk Encryption Utilities """ RD_KEY_FILE = CommonVariables.PassphraseFileNameKey RD_MOUNT_POINT = '/mnt/resource' RD_BASE_DEV_PATH = '/dev/disk/azure/resource' RD_DEV_PATH = '/dev/disk/azure/resource-part1' DM_PREFIX = '/dev/mapper/' # todo: consolidate this and other key file path references # (BekUtil.py, ExtensionParameter.py, and dracut patches) RD_KEY_FILE = '/mnt/azure_bek_disk/LinuxPassPhraseFileName' RD_KEY_FILE_MOUNT_POINT = '/mnt/azure_bek_disk' RD_KEY_VOLUME_LABEL = 'BEK VOLUME' def __init__(self, hutil, logger, distro_patcher): self.hutil = hutil self.logger = logger self.executor = CommandExecutor(self.logger) self.disk_util = DiskUtil(hutil=self.hutil, patching=distro_patcher, logger=self.logger, encryption_environment=None) self.mapper_name = str(uuid.uuid4()) self.mapper_path = self.DM_PREFIX + self.mapper_name def is_encrypt_format_all(self): """ return true if current encryption operation is EncryptFormatAll """ try: public_settings_str = self.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 encryption_operation = public_settings.get( CommonVariables.EncryptionEncryptionOperationKey) if encryption_operation in [ CommonVariables.EnableEncryptionFormatAll ]: return True except: self.logger.log("unable to identify current encryption operation") return False def is_luks_device(self): """ checks if the device is set up with a luks header """ if not self.resource_disk_partition_exists(): return False cmd = 'cryptsetup isLuks ' + self.RD_DEV_PATH return (int)(self.executor.Execute( cmd, suppress_logging=True)) == CommonVariables.process_success def is_luks_device_opened(self): """ check for presence of luks uuid to see if device was already opened """ # suppress logging to avoid log clutter if the device is not open yet if not self.resource_disk_partition_exists(): return False cmd = 'test -b /dev/disk/by-uuid/$(cryptsetup luksUUID ' + self.RD_DEV_PATH + ')' return (int)(self.executor.ExecuteInBash( cmd, suppress_logging=True)) == CommonVariables.process_success def is_valid_key(self): """ test if current key can be used to open current partition """ # suppress logging to avoid log clutter if the key doesn't match if not self.resource_disk_partition_exists(): return False cmd = 'cryptsetup luksOpen ' + self.RD_DEV_PATH + ' --test-passphrase --key-file ' + self.RD_KEY_FILE return (int)(self.executor.Execute( cmd, suppress_logging=True)) == CommonVariables.process_success def resource_disk_exists(self): """ true if the udev name for resource disk exists """ cmd = 'test -b ' + self.RD_BASE_DEV_PATH return (int)(self.executor.Execute( cmd, suppress_logging=True)) == CommonVariables.process_success def resource_disk_partition_exists(self): """ true if udev name for resource disk partition exists """ cmd = 'test -b ' + self.RD_DEV_PATH return (int)(self.executor.Execute( cmd, suppress_logging=True)) == CommonVariables.process_success def format_luks(self): """ set up resource disk crypt device layer using disk util """ if not self.resource_disk_partition_exists(): self.logger.log( 'LUKS format operation requested, but resource disk partition does not exist' ) return False return (int)(self.disk_util.luks_format( passphrase_file=self.RD_KEY_FILE, dev_path=self.RD_DEV_PATH, header_file=None)) == CommonVariables.process_success def encrypt(self): """ use disk util with the appropriate device mapper """ self.mount_key_volume() return (int)(self.disk_util.encrypt_disk( dev_path=self.RD_DEV_PATH, passphrase_file=self.RD_KEY_FILE, mapper_name=self.mapper_name, header_file=None)) == CommonVariables.process_success def make(self): """ make a default file system on top of the crypt layer """ make_result = self.disk_util.format_disk( dev_path=self.mapper_path, file_system=CommonVariables.default_file_system) if make_result != CommonVariables.process_success: self.logger.log(msg="Failed to make file system on ephemeral disk", level=CommonVariables.ErrorLevel) return False # todo - drop DATALOSS_WARNING_README.txt file to disk return True def mount_key_volume(self): """ attempt to mount the key volume and verify existence of key file""" if not os.path.exists(self.RD_KEY_FILE): self.disk_util.make_sure_path_exists(self.RD_KEY_FILE_MOUNT_POINT) key_volume_device_name = os.popen('blkid -L "' + self.RD_KEY_VOLUME_LABEL + '"').read().strip() self.disk_util.mount_filesystem(key_volume_device_name, self.RD_KEY_FILE_MOUNT_POINT) return os.path.exists(self.RD_KEY_FILE) def mount(self): """ mount the file system previously made on top of the crypt layer """ #ensure that resource disk mount point directory has been created cmd = 'mkdir -p ' + self.RD_MOUNT_POINT if self.executor.Execute( cmd, suppress_logging=True) != CommonVariables.process_success: self.logger.log(msg='Failed to precreate mount point directory: ' + cmd, level=CommonVariables.ErrorLevel) return False # mount to mount point directory mount_result = self.disk_util.mount_filesystem( dev_path=self.mapper_path, mount_point=self.RD_MOUNT_POINT, file_system=CommonVariables.default_file_system) if mount_result != CommonVariables.process_success: self.logger.log(msg="Failed to mount file system on resource disk", level=CommonVariables.ErrorLevel) return False return True def configure_waagent(self): """ turn off waagent.conf resource disk management """ # set ResourceDisk.MountPoint to standard mount point cmd = "sed -i.rdbak1 's|ResourceDisk.MountPoint=.*|ResourceDisk.MountPoint=" + self.RD_MOUNT_POINT + "|' /etc/waagent.conf" # set ResourceDiskFormat=n to ensure waagent does not attempt a simultaneous format cmd = "sed -i.rdbak2 's|ResourceDisk.Format=y|ResourceDisk.Format=n|' /etc/waagent.conf" if self.executor.ExecuteInBash(cmd) != CommonVariables.process_success: self.logger.log( msg="Failed to set ResourceDiskFormat in /etc/waagent.conf", level=CommonVariables.WarningLevel) return False # todo: restart waagent if necessary to ensure changes are picked up? return True def configure_fstab(self): """ remove resource disk from /etc/fstab if present """ cmd = "sed -i.bak '/azure_resource-part1/d' /etc/fstab" if self.executor.ExecuteInBash(cmd) != CommonVariables.process_success: self.logger.log( msg="Failed to configure resource disk entry of /etc/fstab", level=CommonVariables.WarningLevel) return False return True def unmount_resource_disk(self): """ unmount resource disk """ # after service healing multiple unmounts of key file mount point may be required self.disk_util.umount(self.RD_KEY_FILE_MOUNT_POINT) self.disk_util.umount(self.RD_KEY_FILE_MOUNT_POINT) self.disk_util.umount(self.RD_MOUNT_POINT) self.disk_util.umount('/mnt') def is_crypt_mounted(self): """ return true if mount point is already on a crypt layer """ mount_items = self.disk_util.get_mount_items() for mount_item in mount_items: if mount_item["dest"] == self.RD_MOUNT_POINT and mount_item[ "src"].startswith(self.DM_PREFIX): return True return False def get_rd_device_mapper(self): """ retrieve current device mapper path backing the encrypted resource disk mount point """ device_items = self.disk_util.get_device_items(self.RD_DEV_PATH) for device_item in device_items: if device_item.type.lower() == 'crypt': self.logger.log('Found device mapper: ' + device_item.name.lower(), level='Info') return device_item.name.lower() return None def remove_device_mapper(self): """ use dmsetup to remove the resource disk device mapper if it exists """ dm_name = self.get_rd_device_mapper() if dm_name: cmd = 'dmsetup remove ' + self.DM_PREFIX + dm_name if self.executor.Execute(cmd) == CommonVariables.process_success: return True else: self.logger.log('failed to remove ' + dm_name) else: self.logger.log('no resource disk device mapper found') return False def prepare_partition(self): """ create partition on resource disk if missing """ if self.resource_disk_partition_exists(): return True self.logger.log("resource disk partition does not exist", level='Info') cmd = 'parted ' + self.RD_BASE_DEV_PATH + ' mkpart primary ext4 0% 100%' if self.executor.ExecuteInBash(cmd) == CommonVariables.process_success: # wait for the corresponding udev name to become available for i in range(0, 10): time.sleep(i) if self.resource_disk_partition_exists(): return True self.logger.log('unable to make resource disk partition') return False def clear_luks_header(self): """ clear luks header by overwriting with 10MB of entropy """ if not self.resource_disk_partition_exists(): self.logger.log( "resource partition does not exist, no luks header to clear") return True cmd = 'dd if=/dev/urandom of=' + self.RD_DEV_PATH + ' bs=512 count=20480' return self.executor.Execute(cmd) == CommonVariables.process_success def try_remount(self): """ mount encrypted resource disk if not already mounted""" if self.is_crypt_mounted(): self.logger.log("resource disk already encrypted and mounted", level='Info') return True if self.resource_disk_exists() and self.resource_disk_partition_exists( ) and self.is_luks_device() and self.is_valid_key(): # store the currently associated path and name current_mapper_name = self.get_rd_device_mapper() if current_mapper_name: self.mapper_name = current_mapper_name self.mapper_path = self.DM_PREFIX + self.mapper_name if not self.is_luks_device_opened: # attempt to open self.disk_util.luks_open(passphrase_file=self.RD_KEY_FILE, dev_path=self.RD_DEV_PATH, mapper_name=self.mapper_name, header_file=None, uses_cleartext_key=False) if not self.is_luks_device_opened: return False # attempt mount return self.mount() # conditions required to re-mount were not met return False def prepare(self): """ prepare a non-encrypted resource disk to be encrypted """ self.configure_waagent() self.configure_fstab() if self.resource_disk_partition_exists(): self.disk_util.swapoff() self.unmount_resource_disk() self.remove_device_mapper() self.clear_luks_header() self.prepare_partition() return True def automount(self): """ encrypt resource disk """ # try to remount if the disk was previously encrypted and is still valid if self.try_remount(): return True # unencrypted or unusable if self.is_encrypt_format_all(): return self.prepare() and self.encrypt() and self.make( ) and self.mount() else: self.logger.log( 'EncryptionFormatAll not in use, resource disk will not be automatically formatted and encrypted.' )
class ResourceDiskUtil(object): """ Resource Disk Encryption Utilities """ RD_KEY_FILE = CommonVariables.PassphraseFileNameKey RD_MOUNT_POINT = '/mnt/resource' RD_BASE_DEV_PATH = '/dev/disk/azure/resource' RD_DEV_PATH = '/dev/disk/azure/resource-part1' DM_PREFIX = '/dev/mapper/' # todo: consolidate this and other key file path references # (BekUtil.py, ExtensionParameter.py, and dracut patches) RD_KEY_FILE = '/mnt/azure_bek_disk/LinuxPassPhraseFileName' RD_KEY_FILE_MOUNT_POINT = '/mnt/azure_bek_disk' RD_KEY_VOLUME_LABEL = 'BEK VOLUME' def __init__(self, hutil, logger, distro_patcher): self.hutil = hutil self.logger = logger self.executor = CommandExecutor(self.logger) self.disk_util = DiskUtil(hutil=self.hutil, patching=distro_patcher, logger=self.logger, encryption_environment=None) self.mapper_name = str(uuid.uuid4()) self.mapper_path = self.DM_PREFIX + self.mapper_name def is_encrypt_format_all(self): """ return true if current encryption operation is EncryptFormatAll """ try: public_settings_str = self.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 encryption_operation = public_settings.get(CommonVariables.EncryptionEncryptionOperationKey) if encryption_operation in [CommonVariables.EnableEncryptionFormatAll]: return True except: self.logger.log("unable to identify current encryption operation") return False def is_luks_device(self): """ checks if the device is set up with a luks header """ if not self.resource_disk_partition_exists(): return False cmd = 'cryptsetup isLuks ' + self.RD_DEV_PATH return (int)(self.executor.Execute(cmd, suppress_logging=True)) == CommonVariables.process_success def is_luks_device_opened(self): """ check for presence of luks uuid to see if device was already opened """ # suppress logging to avoid log clutter if the device is not open yet if not self.resource_disk_partition_exists(): return False cmd = 'test -b /dev/disk/by-uuid/$(cryptsetup luksUUID ' + self.RD_DEV_PATH + ')' return (int)(self.executor.ExecuteInBash(cmd, suppress_logging=True)) == CommonVariables.process_success def is_valid_key(self): """ test if current key can be used to open current partition """ # suppress logging to avoid log clutter if the key doesn't match if not self.resource_disk_partition_exists(): return False cmd = 'cryptsetup luksOpen ' + self.RD_DEV_PATH + ' --test-passphrase --key-file ' + self.RD_KEY_FILE return (int)(self.executor.Execute(cmd, suppress_logging=True)) == CommonVariables.process_success def resource_disk_exists(self): """ true if the udev name for resource disk exists """ cmd = 'test -b ' + self.RD_BASE_DEV_PATH return (int)(self.executor.Execute(cmd, suppress_logging=True)) == CommonVariables.process_success def resource_disk_partition_exists(self): """ true if udev name for resource disk partition exists """ cmd = 'test -b ' + self.RD_DEV_PATH return (int)(self.executor.Execute(cmd, suppress_logging=True)) == CommonVariables.process_success def format_luks(self): """ set up resource disk crypt device layer using disk util """ if not self.resource_disk_partition_exists(): self.logger.log('LUKS format operation requested, but resource disk partition does not exist') return False return (int)(self.disk_util.luks_format(passphrase_file=self.RD_KEY_FILE, dev_path=self.RD_DEV_PATH, header_file=None)) == CommonVariables.process_success def encrypt(self): """ use disk util with the appropriate device mapper """ self.mount_key_volume() return (int)(self.disk_util.encrypt_disk(dev_path=self.RD_DEV_PATH, passphrase_file=self.RD_KEY_FILE, mapper_name=self.mapper_name, header_file=None)) == CommonVariables.process_success def make(self): """ make a default file system on top of the crypt layer """ make_result = self.disk_util.format_disk(dev_path=self.mapper_path, file_system=CommonVariables.default_file_system) if make_result != CommonVariables.process_success: self.logger.log(msg="Failed to make file system on ephemeral disk", level=CommonVariables.ErrorLevel) return False # todo - drop DATALOSS_WARNING_README.txt file to disk return True def mount_key_volume(self): """ attempt to mount the key volume and verify existence of key file""" if not os.path.exists(self.RD_KEY_FILE): self.disk_util.make_sure_path_exists(self.RD_KEY_FILE_MOUNT_POINT) key_volume_device_name = os.popen('blkid -L "' + self.RD_KEY_VOLUME_LABEL + '"').read().strip() self.disk_util.mount_filesystem(key_volume_device_name, self.RD_KEY_FILE_MOUNT_POINT) return os.path.exists(self.RD_KEY_FILE) def mount(self): """ mount the file system previously made on top of the crypt layer """ #ensure that resource disk mount point directory has been created cmd = 'mkdir -p ' + self.RD_MOUNT_POINT if self.executor.Execute(cmd, suppress_logging=True) != CommonVariables.process_success: self.logger.log(msg='Failed to precreate mount point directory: ' + cmd, level=CommonVariables.ErrorLevel) return False # mount to mount point directory mount_result = self.disk_util.mount_filesystem(dev_path=self.mapper_path, mount_point=self.RD_MOUNT_POINT, file_system=CommonVariables.default_file_system) if mount_result != CommonVariables.process_success: self.logger.log(msg="Failed to mount file system on resource disk", level=CommonVariables.ErrorLevel) return False return True def configure_waagent(self): """ turn off waagent.conf resource disk management """ # set ResourceDisk.MountPoint to standard mount point cmd = "sed -i.rdbak1 's|ResourceDisk.MountPoint=.*|ResourceDisk.MountPoint=" + self.RD_MOUNT_POINT + "|' /etc/waagent.conf" # set ResourceDiskFormat=n to ensure waagent does not attempt a simultaneous format cmd = "sed -i.rdbak2 's|ResourceDisk.Format=y|ResourceDisk.Format=n|' /etc/waagent.conf" if self.executor.ExecuteInBash(cmd) != CommonVariables.process_success: self.logger.log(msg="Failed to set ResourceDiskFormat in /etc/waagent.conf", level=CommonVariables.WarningLevel) return False # todo: restart waagent if necessary to ensure changes are picked up? return True def configure_fstab(self): """ remove resource disk from /etc/fstab if present """ cmd = "sed -i.bak '/azure_resource-part1/d' /etc/fstab" if self.executor.ExecuteInBash(cmd) != CommonVariables.process_success: self.logger.log(msg="Failed to configure resource disk entry of /etc/fstab", level=CommonVariables.WarningLevel) return False return True def unmount_resource_disk(self): """ unmount resource disk """ # after service healing multiple unmounts of key file mount point may be required self.disk_util.umount(self.RD_KEY_FILE_MOUNT_POINT) self.disk_util.umount(self.RD_KEY_FILE_MOUNT_POINT) self.disk_util.umount(self.RD_MOUNT_POINT) self.disk_util.umount('/mnt') def is_crypt_mounted(self): """ return true if mount point is already on a crypt layer """ mount_items = self.disk_util.get_mount_items() for mount_item in mount_items: if mount_item["dest"] == self.RD_MOUNT_POINT and mount_item["src"].startswith(self.DM_PREFIX): return True return False def get_rd_device_mapper(self): """ retrieve current device mapper path backing the encrypted resource disk mount point """ device_items = self.disk_util.get_device_items(self.RD_DEV_PATH) for device_item in device_items: if device_item.type.lower() == 'crypt': self.logger.log('Found device mapper: ' + device_item.name.lower(), level='Info') return device_item.name.lower() return None def remove_device_mapper(self): """ use dmsetup to remove the resource disk device mapper if it exists """ dm_name = self.get_rd_device_mapper() if dm_name: cmd = 'dmsetup remove ' + self.DM_PREFIX + dm_name if self.executor.Execute(cmd) == CommonVariables.process_success: return True else: self.logger.log('failed to remove ' + dm_name) else: self.logger.log('no resource disk device mapper found') return False def prepare_partition(self): """ create partition on resource disk if missing """ if self.resource_disk_partition_exists(): return True self.logger.log("resource disk partition does not exist", level='Info') cmd = 'parted ' + self.RD_BASE_DEV_PATH + ' mkpart primary ext4 0% 100%' if self.executor.ExecuteInBash(cmd) == CommonVariables.process_success: # wait for the corresponding udev name to become available for i in range(0, 10): time.sleep(i) if self.resource_disk_partition_exists(): return True self.logger.log('unable to make resource disk partition') return False def clear_luks_header(self): """ clear luks header by overwriting with 10MB of entropy """ if not self.resource_disk_partition_exists(): self.logger.log("resource partition does not exist, no luks header to clear") return True cmd = 'dd if=/dev/urandom of=' + self.RD_DEV_PATH + ' bs=512 count=20480' return self.executor.Execute(cmd) == CommonVariables.process_success def try_remount(self): """ mount encrypted resource disk if not already mounted""" if self.is_crypt_mounted(): self.logger.log("resource disk already encrypted and mounted", level='Info') return True if self.resource_disk_exists() and self.resource_disk_partition_exists() and self.is_luks_device() and self.is_valid_key(): # store the currently associated path and name current_mapper_name = self.get_rd_device_mapper() if current_mapper_name: self.mapper_name = current_mapper_name self.mapper_path = self.DM_PREFIX + self.mapper_name if not self.is_luks_device_opened: # attempt to open self.disk_util.luks_open(passphrase_file=self.RD_KEY_FILE, dev_path=self.RD_DEV_PATH, mapper_name=self.mapper_name, header_file=None, uses_cleartext_key=False) if not self.is_luks_device_opened: return False # attempt mount return self.mount() # conditions required to re-mount were not met return False def prepare(self): """ prepare a non-encrypted resource disk to be encrypted """ self.configure_waagent() self.configure_fstab() if self.resource_disk_partition_exists(): self.disk_util.swapoff() self.unmount_resource_disk() self.remove_device_mapper() self.clear_luks_header() self.prepare_partition() return True def automount(self): """ encrypt resource disk """ # try to remount if the disk was previously encrypted and is still valid if self.try_remount(): return True # unencrypted or unusable if self.is_encrypt_format_all(): return self.prepare() and self.encrypt() and self.make() and self.mount() else: self.logger.log('EncryptionFormatAll not in use, resource disk will not be automatically formatted and encrypted.')
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.')