libvirtd Kerberos
I had some fun getting libvirtd to work with GSSAPI. It looked like it should be easy but documentation was thin on the ground and some key points were glossed over. Eventually I did figure it out. Here’s how.
The first step is to configure libvirtd to accept connections secured with GSSAPI. That means it needs to listen on a TCP port, which it won’t do by default. On my Fedora system that was rectified by editing /etc/sysconfig/libvirtd and uncommenting the line:
LIBVIRTD_ARGS="--listen"
This ensures the –listen flag is passed to libvirtd, enabling TCP connections. That in itself, however, is not enough. For security the default configuration disables unencrypted connections and enables only TLS-encrypted access. Since we’ll be using Kerberos we don’t need TLS. You can leave it on if you have a certificate set up but since I didn’t I turned it off; with no certificate and TLS configured the service won’t start. The file to edit is /etc/libvirt/libvirtd.conf:
listen_tls = 0 listen_tcp = 1
libvirtd uses SASL for GSSAPI so we need the appropriate libraries; on Fedora that means the cyrus-sasl-gssapi RPM. Still in libvirtd.conf we need to configure SASL for unencrypted connections:
auth_tcp = "sasl"
Then we need to set up a whitelist of users who are allowed to connect. Wildcards are allowed so you could just use ["*"] if you wanted anyone with valid Kerberos credentials to get access to the hypervisor. That probably isn’t a good idea.
Note that the comments in libvirtd.conf suggest that you need to use full user principal names in the list. That’s only true for users who are not in the default realm configured in /etc/krb5.conf. Indeed a UPN containing the default realm name will not work.
sasl_allowed_username_list = ["admin", "trusted@ANOTHER.REALM"]
The example above allows admin from the default realm and trusted from the ANOTHER.REALM realm. No one else can connect.
Next we need to tell libvirtd that GSSAPI is a valid security mechanism by editing /etc/sasl2/libvirt.conf. The default configuration allows DIGEST-MD5 so we need to comment out lines referencing that and uncomment the right one:
mech_list: gssapi
Finally – for libvirtd itself – we need to create a keytab for libvirt/<fqdn>@<REALM> and install it as /etc/libvirt/krb5.tab. It need only be accessible to root.
With all that done – and libvirtd restarted – a user with Kerberos credentials matching one of the users allowed above should be able to connect to the hypervisor.
virsh -c qemu+tcp://hostname/system
You can also connect using virt-manager by adding a new connection.
- Connect to remote host
- Method: TCP
- Username: blank
- Hostname: as appropriate
At which point you will find that we’re only half done. VNC needs to be Kerberized separately.
The process is similar. First we need to enable SASL and make sure we are listening, since by default VNC only listens on the loopback interface. This is done in /etc/libvirt/qemu.conf:
vnc_listen = "[::]" vnc_sasl = 1
Since this post was originally made, newer versions of libvirtd changed the syntax of the listen address to :: (no square brackets). If you only need IPv4 networking you can use 0.0.0.0 and of course you can specify a particular address if you prefer.
As with libvirtd, we don’t need TLS with Kerberos.
vnc_tls = 0
We also need to configure /etc/sasl2/qemu.conf in the same way as libvirt.conf:
mech_list: gssapi
And finally we need a keytab installed as /etc/qemu/krb5.tab and readable by the qemu user. Despite conflicting reports in the documentation I found, the service principal name needs to be vnc/<fqdn>@<REALM>.
Newly-started guests will now have their consoles accessible from the Kerberized virt-manager connection.
Note that qemu supports ACLs restricting access to named users but at time of writing libvirt doesn’t know how to configure them. If security is a concern you may prefer to use SSH tunnelling instead. You can use Kerberos and not need to type a password…