Bug 1427049

Summary: [RFE] encrypted volumes support on logical storage pool
Product: Red Hat Enterprise Linux 7 Reporter: Jiri Belka <jbelka>
Component: libvirtAssignee: John Ferlan <jferlan>
Status: CLOSED ERRATA QA Contact: yisun
Severity: low Docs Contact:
Priority: unspecified    
Version: 7.3CC: dyuan, lmen, pkrempa, rbalakri, xuzhang, yalzhang
Target Milestone: rcKeywords: FutureFeature
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: libvirt-3.9.0-1.el7 Doc Type: No Doc Update
Doc Text:
undefined
Story Points: ---
Clone Of: Environment:
Last Closed: 2018-04-10 10:39:40 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Jiri Belka 2017-02-27 08:34:23 UTC
Description of problem:

I tried to create a LUKS volume on a logical storage pool, it seems it is not supported :(

# virsh vol-create ocz-5ef92v58m9be7jo9 /tmp/in
error: Failed to create vol from /tmp/in
error: unsupported configuration: storage pool does not support encrypted volumes

Version-Release number of selected component (if applicable):
libvirt-2.0.0-10.el7_3.4.x86_64

How reproducible:
100%

Steps to Reproduce:
1. create a logical storage pool
2. create a secret and assign it a passphrase
3. create xml definition for a volume with luks encryption
4. vol-create $file

Actual results:
# virsh vol-create ocz-5ef92v58m9be7jo9 /tmp/in
error: Failed to create vol from /tmp/in
error: unsupported configuration: storage pool does not support encrypted volumes


Expected results:
it would be nice to have

Additional info:

Comment 2 John Ferlan 2017-10-06 20:59:48 UTC
Would have been nice to supply some of the details... This is what I've just used in my private branch:

# cat logical.xml
<pool type='logical'>
  <name>bz1427049</name>
  <capacity unit='bytes'>0</capacity>
  <allocation unit='bytes'>0</allocation>
  <available unit='bytes'>0</available>
  <source>
    <device path='/dev/sdh'/>
    <name>bz1427049</name>
    <format type='lvm2'/>
  </source>
  <target>
    <path>/dev/bz1427049</path>
    <permissions>
      <mode>0755</mode>
    </permissions>
  </target>
</pool>

# cat secret.xml
<secret ephemeral='no' private='yes'>
   <description>luks secret for bz1427049 vol1</description>
   <usage type='volume'>
     <volume>/dev/bz1427049/vol1</volume>
   </usage>
</secret>

# cat vol1.xml
<volume>
  <name>vol1</name>
  <capacity unit='M'>500</capacity>
  <target>
    <path>/dev/bz1427049/vol1</path>
    <format type='raw'/>
    <encryption format='luks'>
       <secret type='passphrase' uuid='60cebcc1-20f8-493a-b236-61f7f1211435'/>
       <cipher name='twofish' size='256' mode='cbc' hash='sha256'/>
       <ivgen name='plain64' hash='sha256'/>
    </encryption>
  </target>
</volume>

# virsh secret-define secret.xml
Secret 60cebcc1-20f8-493a-b236-61f7f1211435

# MYSECRET=`printf %s "redhat" | base64`
# virsh secret-set-value 60cebcc1-20f8-493a-b236-61f7f1211435 $MYSECRET
Secret value set

# virsh pool-create logical.xml --build --overwrite
Pool bz1427049 created from logical.xml

# virsh vol-create bz1427049 vol1.xml
Vol vol1 created from vol1.xml

# virsh vol-dumpxml --pool bz1427049 vol1
<volume type='block'>
  <name>vol1</name>
  <key>ckVuvj-plCv-OFAg-gaTT-UD9R-nGYW-J99Zzw</key>
  <source>
    <device path='/dev/sdh'>
      <extent start='0' end='528482304'/>
    </device>
  </source>
  <capacity unit='bytes'>528482304</capacity>
  <allocation unit='bytes'>528482304</allocation>
  <physical unit='bytes'>528482304</physical>
  <target>
    <path>/dev/bz1427049/vol1</path>
    <permissions>
      <mode>0600</mode>
      <owner>0</owner>
      <group>6</group>
      <label>system_u:object_r:fixed_disk_device_t:s0</label>
    </permissions>
    <timestamps>
      <atime>1507319617.581855843</atime>
      <mtime>1507319617.581855843</mtime>
      <ctime>1507319617.581855843</ctime>
    </timestamps>
    <encryption format='luks'>
      <secret type='passphrase' uuid='60cebcc1-20f8-493a-b236-61f7f1211435'/>
      <cipher name='twofish' size='256' mode='cbc' hash='sha256'/>
      <ivgen name='plain64' hash='sha256'/>
    </encryption>
  </target>
</volume>


# lvs bz1427049
  LV   VG        Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  vol1 bz1427049 -wi-a----- 504.00m    
#




The logic I've adjusted will perform the lvcreate using a capacity that is 2MB more than requested in the XML in order to account for the LUKS header. The 504MB size from the lvs output accounts for the 2MB header that LVM adds as well.

Once the LV is created successfully, I'll use qemu-img to apply the LUKS onto the LV... In essence with a 50MB vol1 example:

# lvcreate --name vol1 -L 53248K /dev/bz1427049
# qemu-img create -f luks --object secret,id=sec0,data=`printf %s "redhat" | base64`,format=base64 -o key-secret=sec0 /dev/bz1427049/vol1 512000K

obviously the "redhat" here is just for example purposes.

Once the volume has LUKS on it, using it in a domain will require adding the secret used to create the volume or requiring whomever mounts the volume in the guest to provide the secret. No different than using a file for a LUKS volume.

Patches upstream at:

 https://www.redhat.com/archives/libvir-list/2017-October/msg00340.html

Comment 3 John Ferlan 2017-10-27 09:52:21 UTC
Patch pushed upstream:

commit 2518fd3b6a640ad92630acf9945390ddc1cefd8a
Author: John Ferlan <jferlan>
Date:   Fri Oct 6 16:30:47 2017 -0400

    storage: Allow creation of a LUKS using logical volume
    
    https://bugzilla.redhat.com/show_bug.cgi?id=1427049
    
    Use virStorageBackendCreateVolUsingQemuImg to apply the LUKS information
    to the logical volume just created.  As part of the processing of the
    lvcreate command add 2MB to the capacity to account for the LUKS header
    when it's determined that the volume desires to use encryption.


$ git describe 2518fd3b6a640ad92630acf9945390ddc1cefd8a
CVE-2017-1000256-147-g2518fd3b6a
$

Comment 5 yisun 2017-11-30 08:53:38 UTC
Verified with:
libvirt-3.9.0-3.el7.x86_64
kernel-3.10.0-768.el7.x86_64
qemu-kvm-rhev-2.10.0-9.el7.x86_64

steps:
1. prepare a logical pool
## cat logical.pool
<pool type='logical'>
  <name>lp</name>
  <capacity unit='bytes'>0</capacity>
  <allocation unit='bytes'>0</allocation>
  <available unit='bytes'>0</available>
  <source>
    <device path='/dev/sdc'/>
    <name>logical</name>
    <format type='lvm2'/>
  </source>
  <target>
    <path>/dev/lp</path>
    <permissions>
      <mode>0755</mode>
    </permissions>
  </target>
</pool>


## virsh pool-define logical.pool 
Pool lp defined from logical.pool

## virsh pool-build lp
Pool lp built

## virsh pool-start lp
Pool lp started

2. prepare a libvirt secret
## cat secret.xml 
<secret ephemeral='no' private='yes'>
    <description>luks secret for lp vol1</description>
    <usage type='volume'>
       <volume>/dev/logical/vol1</volume>
    </usage>
</secret>

## virsh secret-define secret.xml 
Secret 1882e21e-23e3-4d11-8a04-98cc392e7bbb created

## MYSECRET=`printf %s "redhat" | base64`

## virsh secret-set-value 1882e21e-23e3-4d11-8a04-98cc392e7bbb $MYSECRET
Secret value set

3. create a vol with luks encryption info
## cat vol1.xml
<volume>
  <name>vol1</name>
  <capacity unit='M'>500</capacity>
  <target>
    <path>/dev/logical/vol1</path>
    <format type='raw'/>
    <encryption format='luks'>
       <secret type='passphrase' uuid='1882e21e-23e3-4d11-8a04-98cc392e7bbb'/>
       <cipher name='twofish' size='256' mode='cbc' hash='sha256'/>
       <ivgen name='plain64' hash='sha256'/>
    </encryption>
  </target>
</volume>

## virsh vol-create lp vol1.xml 
Vol vol1 created from vol1.xml

4. check the vol is actually in luks format
## qemu-img info /dev/logical/vol1
image: /dev/logical/vol1
file format: luks
virtual size: 503M (527429632 bytes)
disk size: 0
encrypted: yes
Format specific information:
    ivgen alg: plain64
    hash alg: sha256
    cipher alg: twofish-256
    uuid: 1f55b44a-5114-4694-8469-6cf67a3799f2
    cipher mode: cbc

5. some extra test
**********************************************************
** use correct libvirt secret to decrypt the luks block ** 
**********************************************************

## virsh edit v
...
    <disk type='block' device='disk'>
      <driver name='qemu' type='raw'/>
      <source dev='/dev/logical/vol1'/>
      <target dev='sdb' bus='scsi'/>
      <encryption format='luks'>
        <secret type='passphrase' uuid='1882e21e-23e3-4d11-8a04-98cc392e7bbb'/>
      </encryption>
      <alias name='scsi0-0-0-1'/>
      <address type='drive' controller='0' bus='0' target='0' unit='1'/>
    </disk>
...

## virsh start v
Domain v started

********************************************
** use libvirt secret with wrong password ** 
********************************************
## cat wrong_pwd_sec.xml 
<secret ephemeral='no' private='yes'>
    <description>luks secret for lp vol1 with wrong password</description>
    <usage type='volume'>
       <volume>/dev/logical/xxx</volume>
    </usage>
</secret>

## virsh secret-define wrong_pwd_sec.xml 
Secret 0d9092b0-6261-4339-991f-f38b16789db1 created

## MYSECRET=`printf %s "greenhat" | base64`

## virsh secret-set-value 0d9092b0-6261-4339-991f-f38b16789db1 $MYSECRET
Secret value set

## virsh edit v
...
    <disk type='block' device='disk'>
      <driver name='qemu' type='raw'/>
      <source dev='/dev/logical/vol1'/>
      <target dev='sdb' bus='scsi'/>
      <encryption format='luks'>
        <secret type='passphrase' uuid='0d9092b0-6261-4339-991f-f38b16789db1'/>
      </encryption>
      <address type='drive' controller='0' bus='0' target='0' unit='1'/>
    </disk>
...

## virsh start v
error: Failed to start domain v
error: internal error: qemu unexpectedly closed the monitor: 2017-11-30T08:07:05.179065Z qemu-kvm: -drive file=/dev/logical/vol1,key-secret=scsi0-0-0-1-luks-secret0,format=luks,if=none,id=drive-scsi0-0-0-1: Invalid password, cannot unlock any keyslot

Comment 9 errata-xmlrpc 2018-04-10 10:39:40 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHEA-2018:0704