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 _create_last_resort(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))
    key = stored_data['data']['dmcrypt_key']
    slot = int(stored_data['data'].get('slot', 0))

    last_slot = 16
    last_key = dmcrypt.generate_key()

    # will raise if any problems with recipients list
    encrypted_last_key = encryption.encrypt(
        last_key, args.recipients.split(',')).decode()

    # be sure values are consistent
    dmcrypt.luks_try_open(key, block_uuid, slot)

    # slot can be empty
    try:
        dmcrypt.luks_kill_slot(key, block_uuid, slot=last_slot)
    except subprocess.CalledProcessError:
        pass

    try:
        dmcrypt.luks_add_key(key, block_uuid, last_key, slot=last_slot)
        dmcrypt.luks_try_open(last_key, block_uuid, last_slot)
    except subprocess.CalledProcessError as luks_error:
        logger.error(
            'LUKS updating {} failed with error code: {}\n'
            'LUKS output: {}'.format(
                block_device,
                luks_error.returncode,
                luks_error.output))
        raise exceptions.LUKSFailure(block_device, luks_error.output)

    if args.print:
        print(encrypted_last_key)

    client.write(vault_path + '-last-resort',
                 key=encrypted_last_key, recipients=args.recipients)
Ejemplo n.º 3
0
def _validate_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 keys for {}'.format(block_uuid))

    if args.mode == 'prev':
        key = stored_data['data'].get('prev_key')
        slot = stored_data['data'].get('prev_slot')
    elif args.mode == 'current':
        key = stored_data['data'].get('dmcrypt_key')
        slot = stored_data['data'].get('slot')
    else:
        raise ValueError("Unrecognized mode '{}'".format(args.mode))

    if key == None or slot == None:
        raise ValueError('Unable to locate {} key for {} ({})'.format(
            args.mode, block_device, block_uuid))

    try:
        dmcrypt.luks_try_open(key, block_uuid, slot)
    except subprocess.CalledProcessError as luks_error:
        logger.error(
            'LUKS {} key on {} ({}) slot {} failed with error code: {}\n'
            'LUKS output: {}'.format(
                args.mode,
                block_device,
                block_uuid,
                slot,
                luks_error.returncode,
                luks_error.output))
        raise exceptions.LUKSFailure(block_device, luks_error.output)
    else:
        print("{} key in vault is valid for {} ({}) slot {}".format(
            args.mode, block_device, block_uuid, slot))
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)