Ejemplo n.º 1
0
def _encrypt_block_device(args, client, config):
    """Encrypt and open a block device

    Stores the dm-crypt key direct in vault

    :param: args: argparser generated cli arguments
    :param: client: hvac.Client for Vault access
    :param: config: configparser object of vaultlocker config
    """
    block_device = args.block_device[0]
    key = dmcrypt.generate_key()
    block_uuid = str(uuid.uuid4()) if not args.uuid else args.uuid
    vault_path = _get_vault_path(block_uuid, config)

    # NOTE: store and validate key before trying to encrypt disk
    try:
        client.write(vault_path,
                     dmcrypt_key=key)
    except hvac.exceptions.VaultError as write_error:
        logger.error(
            'Vault write to path {}. Failed with error: {}'.format(
                vault_path, write_error))
        raise exceptions.VaultWriteError(vault_path, write_error)

    try:
        stored_data = client.read(vault_path)
    except hvac.exceptions.VaultError as read_error:
        logger.error('Vault access to path {}'
                     'failed with error: {}'.format(vault_path, read_error))
        raise exceptions.VaultReadError(vault_path, read_error)

    if not key == stored_data['data']['dmcrypt_key']:
        raise exceptions.VaultKeyMismatch(vault_path)

    # All function calls within try/catch raise a CalledProcessError
    # if return code is non-zero
    # This way if any of the calls fail, the key can be removed from vault
    try:
        dmcrypt.luks_format(key, block_device, block_uuid)
        # Ensure sym link for new encrypted device is created
        # LP Bug #1780332
        dmcrypt.udevadm_rescan(block_device)
        dmcrypt.udevadm_settle(block_uuid)
        dmcrypt.luks_open(key, block_uuid)
    except subprocess.CalledProcessError as luks_error:
        logger.error(
            'LUKS formatting {} failed with error code: {}\n'
            'LUKS output: {}'.format(
                block_device,
                luks_error.returncode,
                luks_error.output))

        try:
            client.delete(vault_path)
        except hvac.exceptions.VaultError as del_error:
            raise exceptions.VaultDeleteError(vault_path, del_error)

        raise exceptions.LUKSFailure(block_device, luks_error.output)

    systemd.enable('vaultlocker-decrypt@{}.service'.format(block_uuid))
Ejemplo n.º 2
0
    def test_vault_write_operation(self, _get_vault_path, _dmcrypt, _systemd):
        _get_vault_path.return_value = 'backend/host/uuid'
        _dmcrypt.generate_key.return_value = 'testkey'

        args = mock.MagicMock()
        args.uuid = 'passed-UUID'
        args.block_device = ['/dev/sdb']

        client = mock.MagicMock()
        client.read.return_value = {'data': {'dmcrypt_key': 'testkey'}}

        self.assertIsNot(
            exceptions.VaultWriteError,
            shell._encrypt_block_device(args, client, self.config))

        client.write.side_effect = exceptions.VaultWriteError(
            'backend/host/uuid', 'Write Failed')
        self.assertRaises(exceptions.VaultWriteError,
                          shell._encrypt_block_device, args, client,
                          self.config)
Ejemplo n.º 3
0
def _vault_kv_write(client, config, vault_path, data):
    try:
        if config.get('vault', 'kv_version') == 'v2':
            client.secrets.kv.v2.create_or_update_secret(
                path=vault_path,
                secret=data,
                cas=None,
                mount_point=config.get('vault', 'kv_mount'),
            )
        else:
            client.secrets.kv.v1.create_or_update_secret(
                path=vault_path,
                secret=data,
                method=None,
                mount_point=config.get('vault', 'kv_mount'),
            )
    except hvac.exceptions.VaultError as write_error:
        logger.error('Vault write to path {}'
                     'failed with error: {}'.format(vault_path, write_error))
        raise exceptions.VaultWriteError(vault_path, write_error)
Ejemplo n.º 4
0
def _rotate_keys(args, client, config):
    block_device, block_uuid = _resolve_device(args.device[0])

    vault_path = _get_vault_path(block_uuid, config)

    stored_data = client.read(vault_path)
    if stored_data is None:
        raise ValueError('Unable to locate key for {}'.format(block_uuid))

    old_key = stored_data['data']['dmcrypt_key']
    old_slot = int(stored_data['data'].get('slot', 0))

    # be sure values are consistent
    dmcrypt.luks_try_open(old_key, block_uuid, old_slot)

    new_slot = 1 if old_slot == 0 else 0
    new_key = dmcrypt.generate_key()

    # slot can be empty at present
    try:
        dmcrypt.luks_kill_slot(old_key, block_uuid, slot=new_slot)
    except subprocess.CalledProcessError:
        pass

    try:
        dmcrypt.luks_add_key(old_key, block_uuid, new_key, slot=new_slot)
    except subprocess.CalledProcessError as luks_error:
        logger.error(
            'LUKS adding {}@{} slot {} failed with error code: {}\n'
            'LUKS output: {}'.format(
                block_uuid,
                block_device,
                new_slot,
                luks_error.returncode,
                luks_error.output))
        raise exceptions.LUKSFailure(block_device, luks_error.output)

    # validating both keys still are valid
    try:
        dmcrypt.luks_try_open(old_key, block_uuid, old_slot)
        dmcrypt.luks_try_open(new_key, block_uuid, new_slot)
    except subprocess.CalledProcessError as luks_error:
        logger.error(
            'LUKS check {}@{} failed with error code: {}\n'
            'LUKS output: {}'.format(
                block_device,
                block_uuid,
                luks_error.returncode,
                luks_error.output))
        raise exceptions.LUKSFailure(block_device, luks_error.output)

    logger.info("writing Vault")
    try:
        client.write(vault_path,
                     dmcrypt_key=new_key, slot=new_slot, prev_key=old_key, prev_slot=old_slot)
    except hvac.exceptions.VaultError as write_error:
        logger.error(
            'Vault write to path {}. Failed with error: {}'.format(
                vault_path, write_error))
        raise exceptions.VaultWriteError(vault_path, write_error)

    try:
        stored_data = client.read(vault_path)
    except hvac.exceptions.VaultError as read_error:
        logger.error('Vault access to path {}'
                     'failed with error: {}'.format(vault_path, read_error))
        raise exceptions.VaultReadError(vault_path, read_error)

    if not new_key == stored_data['data']['dmcrypt_key'] or not old_key == stored_data['data']['prev_key']:
        raise exceptions.VaultKeyMismatch(vault_path)