Re: [Qemu-block] [PATCH 00/17] Framework for securely passing secrets to QEMU

2015-10-23 Thread Stefan Hajnoczi
On Mon, Oct 19, 2015 at 04:09:32PM +0100, Daniel P. Berrange wrote:
> There are a variety of places where QEMU needs to have access
> to passwords, encryption keys or similar kinds of secrets.
> 
>  - VNC / SPICE user passwords
>  - Curl block http / proxy passwords
>  - RBD auth password
>  - iSCSI CHAP password
>  - x509 private key password
>  - QCow/QCow2 encryption key
> 
> QEMU has a variety of ways of dealing with this problem, some
> good, some ugly, some bad.
> 
>  - The RBD block driver accepts the password in plaintext
>via a private RBD config option. This is a pending CVE
> 
> https://security-tracker.debian.org/tracker/CVE-2015-5160
> 
>  - The iSCSI driver accepts the password in plaintext as
>a block driver option. This is the same as the RBD CVE
>essentially, just a QEMU option, rather than a librbd
>option
> 
>  - The VNC / SPICE servers only accept the passwords via
>the QEMU monitor. This is secure, but it inconvenient
>for adhoc developer usage where security of CLI args
>does not matter.
> 
>  - QCow/QCow2 encryption keys can be provided by the monitor
>but this is not available for qemu-img, qemu-io and
>qemu-nbd. QEMU falls back to doing interactive
>console prompting to get keys.
> 
>  - x509 privte key passwords are not supported at all by
>QEMU which forces users to store their key in plaintext
>on their host FS.
> 
>  - The CURL driver doesn't support HTTP auth at all
>currently.
> 
> It is obvious there there is a wide variety of functionality
> in QEMU that needs access to "secrets". This need will only
> grow over time. We need to stop having everyone invent their
> own dangerous wheels and provide a standard mechanism for
> securely passing secrets to QEMU.
> 
> To this end, this series introduces a QCryptoSecret object
> class with short name "secret". All the places which needs
> passwords/keys are then converted to get their via this
> API, except VNC/SPICE which are a future exercise.
> 
> Example usage for creating secrets...
> 
> Direct password, insecure, for ad-hoc developer testing only
> 
>   $QEMU -object secret,id=sec0,data=letmein
> 
> Indirect password via a file, good for production
> 
>   echo -n "letmein" > mypasswd.txt
>   $QEMU -object secret,id=sec0,file=mypasswd.txt
> 
> The file based approach supports file descriptor passing,
> so mgmt apps can use that to dynamically add passwords to
> running QEMU.
> 
> There is a better way though, which is to use an encrypted
> secret. The intent here is that a mgmt app (like libvirt)
> will generate a random AES-256 key for each virtual machine
> it starts (saved in eg /var/run/libvirt/qemu/$GUEST.key)
> It can then use the direct password passing, but encrypt
> the data.
> 
>   $QEMU \
> -object 
> secret,id=secmaster0,file=/var/run/libvirt/qemu/$GUEST.key,format=base64 \
> -object secret,id=sec0,data=[base64 ciphertext],\
>keyid=secmaster0,iv=[base64 initialization vector]
> 
> This means that the mgmt app does not need to worry about
> file descriptor passing at all. It can just use regular
> object properties, safe in the knowledge that the data is
> protected by a secret AES key shared only between QEMU
> and the mgmt app.
> 
> Use of encrypted secrets is not restricted to directly
> provided inline data. If the secret is stored in an
> external file, that can be encrypted too
> 
>   $QEMU \
> -object 
> secret,id=secmaster0,file=/var/run/libvirt/qemu/$GUEST.key,format=base64 \
> -object secret,id=sec0,file=/some/secret/file.aes,\
>keyid=secmaster0,iv=[base64 initialization vector]
> 
> 
> 
> Example usage for referencing secrets...
> 
> CURL:
> 
>   $QEMU -object secret,id=sec0... \
>  -drive driver=http,url=http://example.com/someimg.qcow2,\
>   user=dan,passwordid=sec0
> 
>   $QEMU -object secret,id=sec0... -object secret,id=sec1 \
>  -drive driver=http,url=http://example.com/someimg.qcow2,\
>   user=dan,passwordid=sec0,proxyuser=dan,passwordid=sec1
> 
> iSCSI:
> 
>   $QEMU -object secret,id=sec0... \
>  -drive driver=iscsi,url=iscsi://example.com/target-foo/lun1,\
>  user=dan,passwordid=sec0
> 
> RBD:
> 
>   $QEMU -object secret,id=sec0... \
>  -drive driver=rbd,file=rbd:pool/image:id=myname,\
>  auth-supported-cephx,authsecret=sec0
> 
> QCow/Qcow2 encryption
> 
>   $QEMU -object secret,id=sec0... \
>  -drive file=someimage.qcow2,keyid=sec0
> 
> 
> Finally, this extends qemu-img, qemu-nbd and qemu-io. All of
> them gain a new '--object' parameter which provides the same
> functionality as '-object' with QEMU system emulators. This
> lets us create QCryptoSecret object instances in those tools
> 
> The tools also then get support for a new '--source IMG-OPTS'
> parameter to allow a full set of image options to be specified,
> instead of just separate hardcoded args for format + filename
> which they currently permit. This is probably the

[Qemu-block] [PATCH 00/17] Framework for securely passing secrets to QEMU

2015-10-19 Thread Daniel P. Berrange
There are a variety of places where QEMU needs to have access
to passwords, encryption keys or similar kinds of secrets.

 - VNC / SPICE user passwords
 - Curl block http / proxy passwords
 - RBD auth password
 - iSCSI CHAP password
 - x509 private key password
 - QCow/QCow2 encryption key

QEMU has a variety of ways of dealing with this problem, some
good, some ugly, some bad.

 - The RBD block driver accepts the password in plaintext
   via a private RBD config option. This is a pending CVE

https://security-tracker.debian.org/tracker/CVE-2015-5160

 - The iSCSI driver accepts the password in plaintext as
   a block driver option. This is the same as the RBD CVE
   essentially, just a QEMU option, rather than a librbd
   option

 - The VNC / SPICE servers only accept the passwords via
   the QEMU monitor. This is secure, but it inconvenient
   for adhoc developer usage where security of CLI args
   does not matter.

 - QCow/QCow2 encryption keys can be provided by the monitor
   but this is not available for qemu-img, qemu-io and
   qemu-nbd. QEMU falls back to doing interactive
   console prompting to get keys.

 - x509 privte key passwords are not supported at all by
   QEMU which forces users to store their key in plaintext
   on their host FS.

 - The CURL driver doesn't support HTTP auth at all
   currently.

It is obvious there there is a wide variety of functionality
in QEMU that needs access to "secrets". This need will only
grow over time. We need to stop having everyone invent their
own dangerous wheels and provide a standard mechanism for
securely passing secrets to QEMU.

To this end, this series introduces a QCryptoSecret object
class with short name "secret". All the places which needs
passwords/keys are then converted to get their via this
API, except VNC/SPICE which are a future exercise.

Example usage for creating secrets...

Direct password, insecure, for ad-hoc developer testing only

  $QEMU -object secret,id=sec0,data=letmein

Indirect password via a file, good for production

  echo -n "letmein" > mypasswd.txt
  $QEMU -object secret,id=sec0,file=mypasswd.txt

The file based approach supports file descriptor passing,
so mgmt apps can use that to dynamically add passwords to
running QEMU.

There is a better way though, which is to use an encrypted
secret. The intent here is that a mgmt app (like libvirt)
will generate a random AES-256 key for each virtual machine
it starts (saved in eg /var/run/libvirt/qemu/$GUEST.key)
It can then use the direct password passing, but encrypt
the data.

  $QEMU \
-object 
secret,id=secmaster0,file=/var/run/libvirt/qemu/$GUEST.key,format=base64 \
-object secret,id=sec0,data=[base64 ciphertext],\
   keyid=secmaster0,iv=[base64 initialization vector]

This means that the mgmt app does not need to worry about
file descriptor passing at all. It can just use regular
object properties, safe in the knowledge that the data is
protected by a secret AES key shared only between QEMU
and the mgmt app.

Use of encrypted secrets is not restricted to directly
provided inline data. If the secret is stored in an
external file, that can be encrypted too

  $QEMU \
-object 
secret,id=secmaster0,file=/var/run/libvirt/qemu/$GUEST.key,format=base64 \
-object secret,id=sec0,file=/some/secret/file.aes,\
   keyid=secmaster0,iv=[base64 initialization vector]



Example usage for referencing secrets...

CURL:

  $QEMU -object secret,id=sec0... \
 -drive driver=http,url=http://example.com/someimg.qcow2,\
  user=dan,passwordid=sec0

  $QEMU -object secret,id=sec0... -object secret,id=sec1 \
 -drive driver=http,url=http://example.com/someimg.qcow2,\
  user=dan,passwordid=sec0,proxyuser=dan,passwordid=sec1

iSCSI:

  $QEMU -object secret,id=sec0... \
 -drive driver=iscsi,url=iscsi://example.com/target-foo/lun1,\
 user=dan,passwordid=sec0

RBD:

  $QEMU -object secret,id=sec0... \
 -drive driver=rbd,file=rbd:pool/image:id=myname,\
 auth-supported-cephx,authsecret=sec0

QCow/Qcow2 encryption

  $QEMU -object secret,id=sec0... \
 -drive file=someimage.qcow2,keyid=sec0


Finally, this extends qemu-img, qemu-nbd and qemu-io. All of
them gain a new '--object' parameter which provides the same
functionality as '-object' with QEMU system emulators. This
lets us create QCryptoSecret object instances in those tools

The tools also then get support for a new '--source IMG-OPTS'
parameter to allow a full set of image options to be specified,
instead of just separate hardcoded args for format + filename
which they currently permit. This is probably the area I am
least sure of. I struggled to understand what the "best
practice" is for turning a QemuOpts into something you can
use to instantiate block backends. So I may well have not
done the right thing.

Towards the end I rip out the current encryption key handling
from the block layer so all the hairy code for dealing
with encrypted b