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))
Exemple #3
0
    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.')