Exemple #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)

    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)

    # NOTE: store and validate key
    client.write(vault_path, dmcrypt_key=key)
    stored_data = client.read(vault_path)
    assert key == stored_data['data']['dmcrypt_key']

    dmcrypt.luks_open(key, block_uuid)

    systemd.enable('vaultlocker-decrypt@{}.service'.format(block_uuid))
Exemple #2
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))
Exemple #3
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)
Exemple #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)
 def test_generate_key(self, _os):
     _key = b'randomdatastringfromentropy'
     _os.urandom.return_value = _key
     self.assertEqual(dmcrypt.generate_key(),
                      base64.b64encode(_key).decode('UTF-8'))
     _os.urandom.assert_called_with(dmcrypt.KEY_SIZE / 8)