libvirt: libvirtd: Facilitate using tls connection mode

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@windriver.com>
Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
This commit is contained in:
He Zhe 2019-07-13 12:33:03 +08:00 committed by Bruce Ashfield
parent 990d6d8d2b
commit 37a554a249
3 changed files with 189 additions and 1 deletions

View File

@ -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

View File

@ -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] <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 = 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)

View File

@ -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 += " \