[meta-virtualization] [PATCH] libvirt: libvirtd: Facilitate using tls connection mode

Bruce Ashfield bruce.ashfield at gmail.com
Tue Jul 9 12:17:08 PDT 2019


On Fri, Jul 5, 2019 at 2:22 AM <zhe.he at windriver.com> wrote:
>
> From: He Zhe <zhe.he at windriver.com>
>
> tls is the default network connection mode of libvirtd upstream, though we use
> tcp mode as default.
>
> tls requires necessary keys and certificates of certificate authority, server
> and client to be properly generated and deployed. Otherwise servers and clients
> cannot be connected.
>
> This patch,
>  - integrates sample keys and certificats of certificate authority, server and
>    client for users to be able to use tls mode out of box.
>  - sets default server IP address to 127.0.0.1 for users to use local client out
>    of box.
>  - integrates certtool and provides gnutls-help.py for users to generate keys
>    and certificates on targets in their own ways.
>  - adds a PACKAGECONFIG option "gnutls" to control all of the above integration
>    but disables it to keep the same default behavior as before.
>
> Signed-off-by: He Zhe <zhe.he at windriver.com>
> ---
>  recipes-extended/libvirt/README                   |  26 +++++
>  recipes-extended/libvirt/libvirt/gnutls-helper.py | 130 ++++++++++++++++++++++
>  recipes-extended/libvirt/libvirt_5.3.0.bb         |  28 ++++-
>  3 files changed, 183 insertions(+), 1 deletion(-)
>  create mode 100644 recipes-extended/libvirt/README
>  create mode 100755 recipes-extended/libvirt/libvirt/gnutls-helper.py
>
> diff --git a/recipes-extended/libvirt/README b/recipes-extended/libvirt/README
> new file mode 100644
> index 0000000..af4fd17
> --- /dev/null
> +++ b/recipes-extended/libvirt/README
> @@ -0,0 +1,26 @@
> +libvirt default connection mode between client(where for example virsh runs) and
> +server(where libvirtd runs) is tls which requires keys and certificates for
> +certificate authority, client and server to be properly generated and deployed.
> +Otherwise, servers and clients cannot be connected.
> +
> +recipes-extended/libvirt/libvirt/gnutls-help.py is provided to help generate
> +required keys and certificates.
> +
> +Usage:
> +gnutls-help.py [-a|--ca-info] <ca.info> [-b|--server-info] <server.info> [-c|--client-info] <client.info>
> +If ca.info or server.info or client.info is not provided, a corresponding sample file will be generated.
> +
> +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
> +!! "ip_address" field of server.info must be IP address of the server. !!
> +!! For more details, please refer to:                                  !!
> +!! https://libvirt.org/remote.html#Remote_certificates                 !!
> +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
> +
> +Please deploy cacert.pem     to CA and server and client /etc/pki/CA/cacert.pem
> +Please deploy serverkey.pem  to server /etc/pki/libvirt/private/serverkey.pem
> +Please deploy servercert.pem to server /etc/pki/libvirt/servercert.pem
> +Please deploy clientkey.pem  to client /etc/pki/libvirt/private/clientkey.pem
> +Please deploy clientcert.pem to client /etc/pki/libvirt/clientcert.pem"
> +
> +For more details please refer to libvirt official document,
> +https://libvirt.org/remote.html#Remote_certificates
> diff --git a/recipes-extended/libvirt/libvirt/gnutls-helper.py b/recipes-extended/libvirt/libvirt/gnutls-helper.py
> new file mode 100755
> index 0000000..07acac8
> --- /dev/null
> +++ b/recipes-extended/libvirt/libvirt/gnutls-helper.py
> @@ -0,0 +1,130 @@
> +#!/usr/bin/python

The helper script needs a license header (and copyright if appropriate).

> +import os, sys, getopt
> +
> +banner = \
> +'''\
> +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
> +!! "ip_address" field of server.info must be IP address of the server. !!
> +!! For more details, please refer to:                                  !!
> +!! https://libvirt.org/remote.html#Remote_certificates                 !!
> +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
> +
> +Please deploy cacert.pem     to CA and server and client /etc/pki/CA/cacert.pem
> +Please deploy serverkey.pem  to server /etc/pki/libvirt/private/serverkey.pem
> +Please deploy servercert.pem to server /etc/pki/libvirt/servercert.pem
> +Please deploy clientkey.pem  to client /etc/pki/libvirt/private/clientkey.pem
> +Please deploy clientcert.pem to client /etc/pki/libvirt/clientcert.pem"
> +'''
> +
> +if os.system('which certtool > /dev/null 2>&1') != 0:
> +    print 'certtool is not available. It is provided by \n\
> +gnutls-bin on Yocto like Linux or \n\
> +gnutls-bin on Debian like distribution or \n\
> +gnutls-utils on Redhat like distribution.'
> +    sys.exit()
> +
> +cainfo = ""
> +serverinfo = ""
> +clientinfo = ""
> +yes = 0
> +
> +try:
> +    opts, args = getopt.getopt(sys.argv[1:], "ha:b:c:y", ["help", "ca-info=", "server-info=", "client-info=", "yes"])
> +except getopt.GetoptError:
> +    print 'Usage:\n{} [-a|--ca-info] <ca.info> [-b|--server-info] <server.info> [-c|--client-info] <client.info> [-y|--yes]'.format(sys.argv[0])
> +    print 'If ca.info or server.info or client.info is not provided, a corresponding sample file will be generated.'
> +    sys.exit(2)
> +for opt, arg in opts:
> +    if opt in ("-h", "--help"):
> +        print 'Usage:\n{} [-a|--ca-info] <ca.info> [-b|--server-info] <server.info> [-c|--client-info] <client.info> [-y|--yes]'.format(sys.argv[0])
> +        print 'If ca.info or server.info or client.info is not provided, a corresponding sample file will be generated.\n'
> +        print(banner)
> +        sys.exit()
> +    elif opt in ("-a", "--ca-info"):
> +        cainfo = arg
> +    elif opt in ("-b", "--server-info"):
> +        serverinfo = arg
> +    elif opt in ("-c", "--client-info"):
> +        clientinfo = arg
> +    elif opt in ("-y", "--yes"):
> +        yes = 1
> +
> +cainfodefault = \
> +'''cn = CA
> +ca
> +cert_signing_key
> +'''
> +
> +serverinfodefault = \
> +'''organization = Organization
> +cn = Server
> +dns_name = DNS Name
> +ip_address = 127.0.0.1
> +tls_www_server
> +encryption_key
> +signing_key
> +'''
> +
> +clientinfodefault = \
> +'''country = Country
> +state = State
> +locality = Locality
> +organization = Organization
> +cn = Client
> +tls_www_client
> +encryption_key
> +signing_key
> +'''
> +
> +if not cainfo:
> +    if yes == 0:
> +        opt = raw_input('{}\nca.info not provided by -a, the above will be used [y/n]?'.format(cainfodefault))
> +        if opt != 'y':
> +            exit()
> +    cainfo = "ca.info"
> +    with open(cainfo, mode='w') as f:
> +        f.write(cainfodefault)
> +
> +if not serverinfo:
> +    if yes == 0:
> +        opt = raw_input('{}\nserver.info not provided by -b, the above will be used [y/n]?'.format(serverinfodefault))
> +        if opt != 'y':
> +            exit()
> +    serverinfo = "server.info"
> +    with open(serverinfo, mode='w') as f:
> +        f.write(serverinfodefault)
> +
> +if not clientinfo:
> +    if yes == 0:
> +        opt = raw_input('{}\nclient.info not provided by -c, the above will be used [y/n]?'.format(clientinfodefault))
> +        if opt != 'y':
> +            sys.exit()
> +    clientinfo = "client.info"
> +    with open(clientinfo, mode='w') as f:
> +        f.write(clientinfodefault)
> +
> +if os.system("certtool --generate-privkey > cakey.pem") != 0:
> +    print 'ca private key failed.'
> +    sys.exit()
> +
> +if os.system("certtool --generate-self-signed --load-privkey cakey.pem --template {} --outfile cacert.pem".format(cainfo)) != 0:
> +    print 'ca cert failed.'
> +    sys.exit()
> +
> +if os.system("certtool --generate-privkey > serverkey.pem") != 0:
> +    print 'server private key failed.'
> +    sys.exit()
> +
> +if os.system("certtool --generate-certificate --load-privkey serverkey.pem --load-ca-certificate cacert.pem --load-ca-privkey cakey.pem --template {} --outfile servercert.pem".format(serverinfo)) != 0:
> +    print 'server cert failed.'
> +    sys.exit()
> +
> +if os.system("certtool --generate-privkey > clientkey.pem") != 0:
> +    print 'client private key failed.'
> +    sys.exit()
> +
> +if os.system("certtool --generate-certificate --load-privkey clientkey.pem --load-ca-certificate cacert.pem --load-ca-privkey cakey.pem --template {} --outfile clientcert.pem".format(clientinfo)) != 0:
> +    print 'client cert failed.'
> +    sys.exit()
> +
> +print(banner)
> diff --git a/recipes-extended/libvirt/libvirt_5.3.0.bb b/recipes-extended/libvirt/libvirt_5.3.0.bb
> index c54a99e..9e8dbed 100644
> --- a/recipes-extended/libvirt/libvirt_5.3.0.bb
> +++ b/recipes-extended/libvirt/libvirt_5.3.0.bb
> @@ -8,7 +8,8 @@ SECTION = "console/tools"
>
>  DEPENDS = "bridge-utils gnutls libxml2 lvm2 avahi parted curl libpcap util-linux e2fsprogs pm-utils \
>            iptables dnsmasq readline libtasn1 libxslt-native acl libdevmapper libtirpc \
> -          ${@bb.utils.contains('PACKAGECONFIG', 'polkit', 'shadow-native', '', d)}"
> +          ${@bb.utils.contains('PACKAGECONFIG', 'polkit', 'shadow-native', '', d)} \
> +          ${@bb.utils.contains('PACKAGECONFIG', 'gnutls', 'gnutls-native', '', d)}"
>
>  # libvirt-guests.sh needs gettext.sh
>  #
> @@ -36,6 +37,7 @@ SRC_URI = "http://libvirt.org/sources/libvirt-${PV}.tar.xz;name=libvirt \
>             file://0001-ptest-Remove-Windows-1252-check-from-esxutilstest.patch \
>             file://configure.ac-search-for-rpc-rpc.h-in-the-sysroot.patch \
>             file://hook_support.py \
> +           file://gnutls-helper.py \
>            "
>
>  SRC_URI[libvirt.md5sum] = "1cfaaf3717783ba19850b5ac04f7e76a"
> @@ -119,6 +121,7 @@ FILES_${PN}-libvirtd = " \
>         ${sbindir}/libvirtd \
>         ${systemd_unitdir}/system/* \
>         ${@bb.utils.contains('DISTRO_FEATURES', 'sysvinit', '', '${libexecdir}/libvirt-guests.sh', d)} \
> +       ${@bb.utils.contains('PACKAGECONFIG', 'gnutls', '${sysconfdir}/pki/libvirt/private/cakey.pem ${sysconfdir}/pki/CA/cacert.pem ${sysconfdir}/pki/libvirt/private/serverkey.pem ${sysconfdir}/pki/libvirt/servercert.pem ${sysconfdir}/pki/libvirt/private/clientkey.pem ${sysconfdir}/pki/libvirt/clientcert.pem', '', d)} \

We could use some wildcards and simplify this a bit.

>          "
>
>  FILES_${PN}-virsh = " \
> @@ -198,6 +201,7 @@ PACKAGECONFIG_remove_mipsarchn64 = "qemu"
>
>  # enable,disable,depends,rdepends
>  #
> +PACKAGECONFIG[gnutls] = ",,,gnutls-bin"
>  PACKAGECONFIG[qemu] = "--with-qemu --with-qemu-user=qemu --with-qemu-group=qemu,--without-qemu,qemu,"
>  PACKAGECONFIG[yajl] = "--with-yajl,--without-yajl,yajl,yajl"
>  PACKAGECONFIG[xenapi] = "--with-xenapi,--without-xenapi,,"
> @@ -310,6 +314,28 @@ do_install_append() {
>         chown -R qemu:qemu ${D}/${localstatedir}/lib/libvirt/qemu
>         echo "d qemu qemu 0755 ${localstatedir}/cache/libvirt/qemu none" \
>              >> ${D}${sysconfdir}/default/volatiles/99_libvirt
> +
> +       if ${@bb.utils.contains('PACKAGECONFIG','gnutls','true','false',d)}; then
> +           # Generate sample keys and certificates.
> +           cd ${WORKDIR}
> +           ${WORKDIR}/gnutls-helper.py -y

Since the helper is being run using a python interpreter on the host,
we have an assumption that it is in /usr/bin/python .. we really
should use env and make it more generic, or we will run into host
dependency issues.

Also, I've uprev'd libvirt in master-next. Can you test against that for v2 ?

Bruce

> +
> +           # Deploy all sample keys and certificates of CA, server and client
> +           # to target so that libvirtd is able to boot successfully and local
> +           # connection via 127.0.0.1 is available out of box.
> +           install -d ${D}/etc/pki/CA
> +           install -d ${D}/etc/pki/libvirt/private
> +           install -m 0755 ${WORKDIR}/gnutls-helper.py ${D}/${bindir}
> +           install -m 0644 ${WORKDIR}/cakey.pem ${D}/${sysconfdir}/pki/libvirt/private/cakey.pem
> +           install -m 0644 ${WORKDIR}/cacert.pem ${D}/${sysconfdir}/pki/CA/cacert.pem
> +           install -m 0644 ${WORKDIR}/serverkey.pem ${D}/${sysconfdir}/pki/libvirt/private/serverkey.pem
> +           install -m 0644 ${WORKDIR}/servercert.pem ${D}/${sysconfdir}/pki/libvirt/servercert.pem
> +           install -m 0644 ${WORKDIR}/clientkey.pem ${D}/${sysconfdir}/pki/libvirt/private/clientkey.pem
> +           install -m 0644 ${WORKDIR}/clientcert.pem ${D}/${sysconfdir}/pki/libvirt/clientcert.pem
> +
> +           # Force the connection to be tls.
> +           sed -i -e 's/^\(listen_tls\ =\ .*\)/#\1/' -e 's/^\(listen_tcp\ =\ .*\)/#\1/' ${D}/etc/libvirt/libvirtd.conf
> +       fi
>  }
>
>  EXTRA_OECONF += " \
> --
> 2.7.4
>


-- 
- Thou shalt not follow the NULL pointer, for chaos and madness await
thee at its end
- "Use the force Harry" - Gandalf, Star Trek II


More information about the meta-virtualization mailing list