Ejemplo n.º 1
0
 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)
Ejemplo n.º 2
0
 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
Ejemplo n.º 3
0
 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
Ejemplo n.º 5
0
 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):
     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
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
 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()
Ejemplo n.º 9
0
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.')
             
Ejemplo n.º 11
0
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")
Ejemplo n.º 12
0
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.')