diff --git a/recipes-extended/libvirt/README b/recipes-extended/libvirt/README new file mode 100644 index 00000000..af4fd170 --- /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] [-b|--server-info] [-c|--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 00000000..b9949469 --- /dev/null +++ b/recipes-extended/libvirt/libvirt/gnutls-helper.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 Wind River Systems, Inc. +# +# SPDX-License-Identifier: GPL-2.0-only +# + +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] [-b|--server-info] [-c|--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] [-b|--server-info] [-c|--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 = 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 = 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 = 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.5.0.bb b/recipes-extended/libvirt/libvirt_5.5.0.bb index 7ed40a64..8d718628 100644 --- a/recipes-extended/libvirt/libvirt_5.5.0.bb +++ b/recipes-extended/libvirt/libvirt_5.5.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] = "27c5fb6c8d2d46eb9e8165aeb3b499b0" @@ -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/* ${sysconfdir}/pki/CA/*', '', d)} \ " 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 + + # 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 += " \