Bug 1662412 - [RFE]blockdev-create: backing-encrypt.key-secret is needed for opening luks/luks-inside-qcow2 backing image
Summary: [RFE]blockdev-create: backing-encrypt.key-secret is needed for opening luks/l...
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Red Hat Enterprise Linux Advanced Virtualization
Classification: Red Hat
Component: qemu-kvm
Version: 8.1
Hardware: Unspecified
OS: Unspecified
high
high
Target Milestone: rc
: 8.0
Assignee: Maxim Levitsky
QA Contact: aihua liang
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2018-12-28 08:56 UTC by aihua liang
Modified: 2019-11-19 06:37 UTC (History)
8 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2019-11-13 05:22:38 UTC
Type: Feature Request
Target Upstream Version:


Attachments (Terms of Use)
demo script (2.66 KB, text/plain)
2019-09-30 10:46 UTC, Maxim Levitsky
no flags Details

Description aihua liang 2018-12-28 08:56:36 UTC
Description of problem:
  blockdev-create: backing-encrypt.key-secret is needed.

Version-Release number of selected component (if applicable):
  kernel version:4.18.0-57.el8.x86_64
  qemu-kvm version:qemu-kvm-3.1.0-2.module+el8+2606+2c716ad7.x86_64

How reproducible:
 100%

Steps to Reproduce:
1.Start guest with imageformat "luks-inside-qcow2":
   /usr/libexec/qemu-kvm \
    -name 'avocado-vt-vm1' \
    -machine pc  \
    -nodefaults \
    -device VGA,bus=pci.0 \
    -chardev socket,id=qmp_id_qmpmonitor1,path=/var/tmp/monitor-qmpmonitor1-20181225-045358-gDqDsfCu,server,nowait \
    -mon chardev=qmp_id_qmpmonitor1,mode=control  \
    -chardev socket,id=qmp_id_catch_monitor,path=/var/tmp/monitor-catch_monitor-20181225-045358-gDqDsfCu,server,nowait \
    -mon chardev=qmp_id_catch_monitor,mode=control \
    -device pvpanic,ioport=0x505,id=idHtZPbY  \
    -chardev socket,id=serial_id_serial0,path=/var/tmp/serial-serial0-20181225-045358-gDqDsfCu,server,nowait \
    -device isa-serial,chardev=serial_id_serial0  \
    -chardev socket,id=seabioslog_id_20181225-045358-gDqDsfCu,path=/var/tmp/seabios-20181225-045358-gDqDsfCu,server,nowait \
    -device isa-debugcon,chardev=seabioslog_id_20181225-045358-gDqDsfCu,iobase=0x402 \
    -device qemu-xhci,id=usb1,bus=pci.0 \
    -object secret,id=sec0,data=backing \
    -blockdev driver=file,node-name=driveimage1,filename=/home/kvm_autotest_root/images/rhel8.qcow2 \
    -blockdev node-name=drive_image1,file=driveimage1,driver=qcow2,encrypt.key-secret=sec0,encrypt.format=luks \
    -device virtio-blk-pci,id=image1,drive=drive_image1,bootindex=0,bus=pci.0 \
    -device virtio-net-pci,mac=9a:14:15:16:17:18,id=idQJqHNz,vectors=4,netdev=idXGWoum,bus=pci.0  \
    -netdev tap,id=idXGWoum,vhost=on \
    -m 14336  \
    -smp 10,maxcpus=10,cores=5,threads=1,sockets=2  \
    -cpu 'Broadwell',+kvm_pv_unhalt \
    -device usb-tablet,id=usb-tablet1,bus=usb1.0,port=1  \
    -vnc :0  \
    -rtc base=utc,clock=host,driftfix=slew  \
    -boot order=cdn,once=c,menu=off,strict=off \
    -enable-kvm \
    -monitor stdio \
    -qmp tcp:0:3000,server,nowait \
    -blockdev driver=file,node-name=drivedata1,filename=/home/data1.qcow2 \
    -blockdev node-name=drive_data1,file=drivedata1,driver=qcow2,encrypt.key-secret=sec0,encrypt.format=luks \
    -device virtio-blk-pci,id=data1,drive=drive_data1,bus=pci.0 \
    -blockdev driver=file,node-name=drivedata2,filename=/home/data2.qcow2 \
    -blockdev node-name=drive_data2,file=drivedata2,driver=qcow2 \
    -device virtio-blk-pci,id=data2,drive=drive_data2,bus=pci.0 \

2. Create an image in previous for full backup.
   {'execute':'blockdev-create','arguments':{'options': {'driver':'file','filename':'/root/sn1','size':1073741824},'job-id':'job1'}}
   {'execute':'blockdev-add','arguments':{'driver':'file','node-name':'drive_sn1','filename':'/root/sn1'}}
   {'execute':'blockdev-create','arguments':{'options': {'driver': 'qcow2','file':'drive_sn1','size':1073741824,'encrypt':{'key-secret':'sec0', 'format': 'luks'}},'job-id':'job2'}}
   {'execute':'blockdev-add','arguments':{'driver':'qcow2','node-name':'sn1','file':'drive_sn1','encrypt': {'key-secret':'sec0','format': 'luks'}}}
   {'execute':'job-dismiss','arguments':{'id':'job1'}}
   {'execute':'job-dismiss','arguments':{'id':'job2'}}

3. Do full backup and add bitmap "bitmap1"
   {"execute": "transaction", "arguments": { "actions": [ {"type": "blockdev-backup", "data": { "device": "drive_data1", "target": "sn1", "sync": "full", "job-id":"j1" } }, {"type": "block-dirty-bitmap-add", "data": { "node": "drive_data1", "name": "bitmap1" } } ] } }

4. Do dd in guest.
  (guest)#mkfs.ext4 /dev/vdb
         #mount /dev/vdb /mnt/a
         #cd /mnt/a
         #dd if=/dev/urandom of=a bs=1M count=1 oflag=dsync

5. Create image for incremental live backup.
     {'execute':'blockdev-create','arguments':{'options': {'driver':'file','filename':'/root/sn2','size':1073741824},'job-id':'job1'}}" >&3
     {'execute':'blockdev-add','arguments':{'driver':'file','node-name':'drive_sn2','filename':'/root/sn2'}}
     {'execute':'blockdev-create','arguments':{'options': {'driver': 'qcow2','file':'drive_sn2','size':1073741824,'encrypt': {'key-secret': 'sec0', 'format': 'luks'},'backing-file':'/root/sn1','backing-fmt':'qcow2'},'job-id':'job2'}}
     {'execute':'blockdev-add','arguments':{'driver':'qcow2','node-name':'sn2','file':'drive_sn2','encrypt': {'key-secret': 'sec0', 'format': 'luks'},'backing':'sn1'}}
     {'execute':'job-dismiss','arguments':{'id':'job1'}}
     {'execute':'job-dismiss','arguments':{'id':'job2'}}

6. Do incremental live backup.
    {"execute":"blockdev-backup","arguments":{"device":"drive_data1","target":"sn2","sync":"incremental","bitmap":"bitmap1","job-id":"j1"}}

7. After backup finished,start guest with sn2.
    ...
    -blockdev driver=file,node-name=drivedata1,filename=/root/sn2 \
    -blockdev node-name=drive_data1,file=drivedata1,driver=qcow2,encrypt.key-secret=sec0,encrypt.format=luks \
    -device virtio-blk-pci,id=data1,drive=drive_data1,bus=pci.0 \
    ...

Actual results:

 After step7, guest failed to start with error msg:
   [root@ibm-x3650m5-07 home]# sh live_backup_sn.txt
qemu-kvm: -blockdev node-name=drive_data1,file=drivedata1,driver=qcow2,encrypt.key-secret=sec0,encrypt.format=luks: Could not open backing file: Parameter 'encrypt.key-secret' is required for cipher

 #[root@ibm-x3650m5-07 ~]# qemu-img info sn2 
image: sn2
file format: qcow2
virtual size: 20G (21474836480 bytes)
disk size: 540K
encrypted: yes
cluster_size: 65536
backing file: /root/sn1
backing file format: qcow2
Format specific information:
    compat: 1.1
    lazy refcounts: false
    refcount bits: 16
    encrypt:
        ivgen alg: plain64
        hash alg: sha256
        cipher alg: aes-256
        uuid: 56a65661-eb15-4937-9587-54000efc8adb
        format: luks
        cipher mode: xts
        slots:
            [0]:
                active: true
                iters: 1397544
                key offset: 4096
                stripes: 4000
            [1]:
                active: false
                key offset: 262144
            [2]:
                active: false
                key offset: 520192
            [3]:
                active: false
                key offset: 778240
            [4]:
                active: false
                key offset: 1036288
            [5]:
                active: false
                key offset: 1294336
            [6]:
                active: false
                key offset: 1552384
            [7]:
                active: false
                key offset: 1810432
        payload offset: 2068480
        master key iters: 328008
    corrupt: false


Expected results:
  Can start guest with the incremental image.

Additional info:
  operations like qemu-img compare also have this issue.

Comment 2 Ademar Reis 2019-01-03 16:29:08 UTC
See also: BZ 1625604

Comment 4 Maxim Levitsky 2019-09-30 08:05:14 UTC
Basically the problem here is that qemu-img doesn't have the flexibility
to create all the backing chain, but rather only supports chain of length of 2
(that is leaf image and its immediate backing file)

The problem is that backing chain length is not bound, and for each node,
the user can supply various parameters, including which encryption key to use.
the qmp blockdev-add/blockdev-create solves this in the right way.

Another thought is that if block devices in the backing chain all have different passwords,
the external application managing it would have hard time tracking all these passwords.

Also note that qemu-img sort of can open a qcow2 image encrypted with one password,
while its backing file encrypted with another password, if the backing file
is stored in json form in the snapshot qcow2. This is ugly as hell, since in this case,
the backing file contains the 'secret id', which might already be in use, and short of
modifying the backing file in the actual qcow2 image, you have to supply secret with that id.

Example:

qemu-img info ./sn1.qcow2 
image: ./sn1.qcow2
file format: qcow2
virtual size: 500M (524288000 bytes)
disk size: 258M
encrypted: yes
cluster_size: 65536
backing file: json:{
        "encrypt.key-secret": "sec1", 
        "driver": "qcow2", 
        "file": { "driver": "file", "filename": "base2.qcow2"}
    }
backing file format: qcow2
Format specific information:


The whole thing really needs discussion on the mailing list,
and I would say, it might be a good idea to start writing
a replacement for qemu-img which would be much more aligned with
blockdev-* interfaces.

Comment 5 Maxim Levitsky 2019-09-30 10:46:09 UTC
Created attachment 1621043 [details]
demo script

Another thing worth noting is that you can right now specify the whole backing chain if you use the 'json' syntax,
thus I think that this bug should actually be closed.

I attach a quick and dirty shell script which demonstrates this feature.

One thing that we should improve I think, but not related to this bug,
is that when you specify backing file as a json, it encodes the whole
of it into the image which might not be desired

Comment 8 aihua liang 2019-10-09 10:15:11 UTC
Hi, Maxim
  
   Thanks for your script, i tried it and it works ok for qemu-img + luks/luks-inside-qcow2 operations with different/same encryption key on snapshots chain.
   
   As you described in comment4, the key point to open an encrypted backing file is that the snapshot node should contain the backing encryption info in json format, like:
#qemu-img info ./sn1.qcow2
image: ./sn1.qcow2
....
backing file: json:{
        "encrypt.key-secret": "sec1", 
        "driver": "qcow2", 
        "file": { "driver": "file", "filename": "base2.qcow2"}
    }

So the question is:
   How can i add this info to my snapshot node by blockdev-create? 
   At present, only params 'backing-file'and 'backing-fmt' supported in blockdev-create.
   {'execute':'blockdev-create','arguments':{'options': {'driver': 'qcow2','file':'drive_sn2','size':1073741824,'encrypt': {'key-secret': 'sec0', 'format': 'luks'},'backing-file':'/root/sn1','backing-fmt':'qcow2'},'job-id':'job2'}}

When switch to -blockdev, 'blockdev-create' not 'qemu-img' is suggested to use for nodes creation during block jobs operations, so i think a solution for this issue is needed.


BR,
aliang

Comment 9 Maxim Levitsky 2019-11-05 10:27:25 UTC
Hi!

For blockdev-create, the backing-file is a string which is written as is to the qcow2 file. I think it can be a json blob as well, just like in case of qemu-img create.

Or, it is also possible to not specify a backing file at all, but specify it explicitly when opening the block devices (that needs some external means of tracking the backing chain.
This is possible because blockdev-add qmp command accepts an already opened blockdev for both backing file, thus you can open the whatever qcow2 image you know is a backing file and use
a whatever password that is needed to do so and then open the image itsel and specify that opened block device as the backing file.

Comment 10 aihua liang 2019-11-11 09:16:55 UTC
(In reply to Maxim Levitsky from comment #9)
> Hi!
Sorry for the late reply, just back from Shanghai Open Stack submit meeting.
> 
> For blockdev-create, the backing-file is a string which is written as is to
> the qcow2 file. I think it can be a json blob as well, just like in case of
> qemu-img create.

Maxim, I tried with json format, but still failed:
 
{'execute':'blockdev-create','arguments':{'options': {'driver': 'qcow2','file':'drive_sn1','size':21474836480,'encrypt': {'key-secret': 'sec0', 'format': 'luks'},'backing':{'driver':'qcow2','file':'/home/kvm_autotest_root/images/rhel8.luks','encrypt.key-secret':'sec0'}},'job-id':'job2'}}
{"error": {"class": "GenericError", "desc": "Parameter 'options.backing' is unexpected"}}

Any error in my command?
 
> 
> Or, it is also possible to not specify a backing file at all, but specify it
> explicitly when opening the block devices (that needs some external means of
> tracking the backing chain.
How to? Can you give me an example?

Work flow for my block jobs always be:
    create image online--> add this new node to node graph by blockdev-add --> do block jobs on this node(like snapshot)

It seems opening the node will be the final step...:)

> This is possible because blockdev-add qmp command accepts an already opened
> blockdev for both backing file, thus you can open the whatever qcow2 image
> you know is a backing file and use
> a whatever password that is needed to do so and then open the image itsel
> and specify that opened block device as the backing file.


BR,
aliang

Comment 11 Maxim Levitsky 2019-11-11 11:19:28 UTC
Yes. The backing file should be  a string, but in json format.

It should be something like

'backing':"json://{'driver':'qcow2','file':'/home/kvm_autotest_root/images/rhel8.luks','encrypt.key-secret':'sec0'}"

or something like that

Best regards,
    Maxim Levitsky

Comment 16 aihua liang 2019-11-13 05:22:38 UTC
It's an usage error for image creation with encrypted backing file, update its steps bellow, and close this bug as "NOTABUG".


Test Steps:
  1.Start guest with imageformat "luks-inside-qcow2":
   /usr/libexec/qemu-kvm \
    -name 'avocado-vt-vm1' \
    -machine pc  \
    -nodefaults \
    -device VGA,bus=pci.0 \
    -chardev socket,id=qmp_id_qmpmonitor1,path=/var/tmp/monitor-qmpmonitor1-20181225-045358-gDqDsfCu,server,nowait \
    -mon chardev=qmp_id_qmpmonitor1,mode=control  \
    -chardev socket,id=qmp_id_catch_monitor,path=/var/tmp/monitor-catch_monitor-20181225-045358-gDqDsfCu,server,nowait \
    -mon chardev=qmp_id_catch_monitor,mode=control \
    -device pvpanic,ioport=0x505,id=idHtZPbY  \
    -chardev socket,id=serial_id_serial0,path=/var/tmp/serial-serial0-20181225-045358-gDqDsfCu,server,nowait \
    -device isa-serial,chardev=serial_id_serial0  \
    -chardev socket,id=seabioslog_id_20181225-045358-gDqDsfCu,path=/var/tmp/seabios-20181225-045358-gDqDsfCu,server,nowait \
    -device isa-debugcon,chardev=seabioslog_id_20181225-045358-gDqDsfCu,iobase=0x402 \
    -device qemu-xhci,id=usb1,bus=pci.0 \
    -object secret,id=sec0,data=backing \
    -blockdev driver=file,node-name=driveimage1,filename=/home/kvm_autotest_root/images/rhel8.qcow2 \
    -blockdev node-name=drive_image1,file=driveimage1,driver=qcow2,encrypt.key-secret=sec0,encrypt.format=luks \
    -device virtio-blk-pci,id=image1,drive=drive_image1,bootindex=0,bus=pci.0 \
    -device virtio-net-pci,mac=9a:14:15:16:17:18,id=idQJqHNz,vectors=4,netdev=idXGWoum,bus=pci.0  \
    -netdev tap,id=idXGWoum,vhost=on \
    -m 14336  \
    -smp 10,maxcpus=10,cores=5,threads=1,sockets=2  \
    -cpu 'Broadwell',+kvm_pv_unhalt \
    -device usb-tablet,id=usb-tablet1,bus=usb1.0,port=1  \
    -vnc :0  \
    -rtc base=utc,clock=host,driftfix=slew  \
    -boot order=cdn,once=c,menu=off,strict=off \
    -enable-kvm \
    -monitor stdio \
    -qmp tcp:0:3000,server,nowait \
    -blockdev driver=file,node-name=drivedata1,filename=/home/data1.qcow2 \
    -blockdev node-name=drive_data1,file=drivedata1,driver=qcow2,encrypt.key-secret=sec0,encrypt.format=luks \
    -device virtio-blk-pci,id=data1,drive=drive_data1,bus=pci.0 \
    -blockdev driver=file,node-name=drivedata2,filename=/home/data2.qcow2 \
    -blockdev node-name=drive_data2,file=drivedata2,driver=qcow2 \
    -device virtio-blk-pci,id=data2,drive=drive_data2,bus=pci.0 \

  2. Create an image in previous for full backup.
   {'execute':'blockdev-create','arguments':{'options': {'driver':'file','filename':'/root/sn1','size':1073741824},'job-id':'job1'}}
   {'execute':'blockdev-add','arguments':{'driver':'file','node-name':'drive_sn1','filename':'/root/sn1'}}
   {'execute':'blockdev-create','arguments':{'options': {'driver': 'qcow2','file':'drive_sn1','size':1073741824,'encrypt':{'key-secret':'sec0', 'format': 'luks'}},'job-id':'job2'}}
   {'execute':'blockdev-add','arguments':{'driver':'qcow2','node-name':'sn1','file':'drive_sn1','encrypt': {'key-secret':'sec0','format': 'luks'}}}
   {'execute':'job-dismiss','arguments':{'id':'job1'}}
   {'execute':'job-dismiss','arguments':{'id':'job2'}}

  3. Do full backup and add bitmap "bitmap1"
   {"execute": "transaction", "arguments": { "actions": [ {"type": "blockdev-backup", "data": { "device": "drive_image1", "target": "sn1", "sync": "full", "job-id":"j1" } }, {"type": "block-dirty-bitmap-add", "data": { "node": "drive_image1", "name": "bitmap1" } } ] } }

  4. Do dd in guest.
  (guest)#dd if=/dev/urandom of=a bs=1M count=1 oflag=dsync

  5. Create image for incremental live backup.
     {'execute':'blockdev-create','arguments':{'options': {'driver':'file','filename':'/root/sn2','size':1073741824},'job-id':'job1'}}" >&3
     {'execute':'blockdev-add','arguments':{'driver':'file','node-name':'drive_sn2','filename':'/root/sn2'}}
     {'execute':'blockdev-create','arguments':{'options': {'driver': 'qcow2','file':'drive_sn2','size':1073741824,'encrypt': {'key-secret': 'sec0', 'format': 'luks'},'backing-file':"json:{'driver':'qcow2','file':{'driver':'file','filename':'/root/sn1'},'encrypt.key-secret':'sec0'}",'backing-fmt':'qcow2'},'job-id':'job2'}}
     {'execute':'blockdev-add','arguments':{'driver':'qcow2','node-name':'sn2','file':'drive_sn2','encrypt': {'key-secret': 'sec0', 'format': 'luks'},'backing':'sn1'}}
     {'execute':'job-dismiss','arguments':{'id':'job1'}}
     {'execute':'job-dismiss','arguments':{'id':'job2'}}

  6. Do incremental live backup.
    {"execute":"blockdev-backup","arguments":{"device":"drive_image1","target":"sn2","sync":"incremental","bitmap":"bitmap1","job-id":"j1"}}

  7. Check sn2 image info:
  #qemu-img info /root/sn2
   image: /root/sn2
file format: qcow2
virtual size: 20G (21474836480 bytes)
disk size: 8.5M
encrypted: yes
cluster_size: 65536
backing file: json:{'driver':'qcow2','file':{'driver':'file','filename':'/root/sn1'},'encrypt.key-secret':'sec0'}
backing file format: qcow2
Format specific information:
    compat: 1.1
    lazy refcounts: false
    refcount bits: 16
    encrypt:
        ivgen alg: plain64
        hash alg: sha256
        cipher alg: aes-256
        uuid: 8ff66f21-2c95-4326-a868-19da40d6a826
        format: luks
        cipher mode: xts
        slots:
            [0]:
                active: true
                iters: 100206
                key offset: 4096
                stripes: 4000
            [1]:
                active: false
                key offset: 262144
            [2]:
                active: false
                key offset: 520192
            [3]:
                active: false
                key offset: 778240
            [4]:
                active: false
                key offset: 1036288
            [5]:
                active: false
                key offset: 1294336
            [6]:
                active: false
                key offset: 1552384
            [7]:
                active: false
                key offset: 1810432
        payload offset: 2068480
        master key iters: 25634
    corrupt: false

  8. After backup finished,start guest with sn2.
    ...
    -blockdev driver=file,node-name=drivedata1,filename=/root/sn2 \
    -blockdev node-name=drive_data1,file=drivedata1,driver=qcow2,encrypt.key-secret=sec0,encrypt.format=luks \
    -device virtio-blk-pci,id=data1,drive=drive_data1,bus=pci.0 \
    ...

Test Result:
  After step8, guest can start up successfully.


Note You need to log in before you can comment on or make changes to this bug.