KVM/Qemu VMs with a multi-screen Spice console – VII – remote-viewer, qemu and SASL authentication

I continue with my exploration of remote access methods to the Spice console of a VM run on a KVM/Qemu-server with Opensuse Leap 15.2 as OS.

KVM/Qemu VMs with a multi-screen Spice console – VI – remote access with remote-viewer and TLS encryption
KVM/Qemu VMs with a multi-screen Spice console – V – remote access via remote-viewer, a network port and a SSH-tunnel
KVM/Qemu VMs with a multi-screen Spice console – IV – remote access via SSH, remote-viewer and a Unix socket
KVM/Qemu VMs with a multi-screen Spice console – III – local access with remote-viewer via a Unix socket
KVM/Qemu VMs with a multi-screen Spice console – II – local access with remote-viewer via a network port
KVM/Qemu VMs with a multi-screen Spice console – I – Overview over local and remote access methods

The topic of my last post was the combination of remote-viewer with "TLS" encryption. We configured libvirt such that virt-manager or virsh started the qemu-process for our test-VM with support for TLS/SSL. But: Remote-viewer itself does not use any libvirt-layer; regarding connections to a VM-specific network port, it is the qemu-emulator-process of the VM which does the encryption business for us on the server's side - not libvirt.

In comparison to SSH-based methods discussed earlier a major disadvantage of the TLS-solution was the lack of any authentication on the server. The TLS-port for Spice on the server was open for anybody in our Intranet - not a nice situation for a "one seat" tool as Spice. We could, of course, have restricted access to certain client-systems by a firewall and by setting a general or a VM-specific password for the Spice console(s); but still there would not be any user-specific restrictions in place.

As a first improvement we would like to establish some server-side authentication as a condition for access to a Spice console. With SSH this was a peace of cake - and we could in addition set user-specific options for the SSH daemon to combine authentication with a user-specific access to the Spice console of a selected VM, only. Something similar is much harder to achieve with TLS - as long as we cling to libvirt-tools for starting VMs and remote-viewer as a client. I have not succeeded with it by simple means. Actually, I will need another article to describe some measures for real user specific restrictions - on the remote-client and, unfortunately, without reaching the same clear association of a user's authentication on the server with the access to a specific VM. But one step after the other.

In this article I am going to discuss the combination of

remote-viewer, Qemu, TLS and SASL.

We first take a look at a most simple SASL authentication mechanisms based on a sasldb2-file which contains the credentials. One could also directly involve a Kerberos system by just changing some settings in prepared configuration files. But Kerberos is beyond the scope of this series. Instead I want to show you how to configure the invocation of the saslauthd daemon as a general bridge to whatever authentication method you prefer in your network or on the server for special services. For reasons of simplicity we pick the local PAM machinery on the server as an example, but MySQL, LDAP or LDAP combined with Kerberos would be other options.

We are going to see that these two simple approaches to SASL based authentication - though working - come with a big disadvantage regarding Spice: The authentication is unfortunately global for all VMs. We won't get a restriction to the Spice console of a specific VM with remote-viewer and SASL. And we do not really restrict the access to the console of a specific VM to a defined UID on the server.

But, let us first focus on the problem of getting SASL active in combination with remote-viewer. We work again with our test-VM "debianx" with a Kali system on it, a laptop MyLAP as a remote client-system with OS Leap 15.2 and a KVM/Qemu server, also with Opensuse Leap 15.2 as OS (see the previous articles of this series).

Schematic overview

The following drawing gives you an overview about the involved components on the KVM/Qemu server and on the remote client-system.

This is more or less the graphics from my last article with additional elements. I have indicated that both remote-viewer and the Qemu-hypervisor must be configured to use SASL in addition to OpenSSL. This in turn means that these components must support SASL and its challenge/response mechanisms. On the server-side we need a SASL compatible backend for keeping credential data and performing authentication against them. Some Qemu-configuration options allow for a direct and seamless access of certain backends - as sasldb2 or Kerberos. However, the "saslauthd" daemon with its manifold of connectors to different internal or external backends can be used as a mediator, too.

Note that we would create severe security holes if SASL related credentials or other authentication data were transferred between the client-system and the server without encryption. SASL is basically independent of OpenSSL-libraries. It provides its own methods ("mechanisms") for data exchange - some with encryption, but some without. And saslauthd works with clear text data, only.

Therefore, any client-application using SASL is well advised to check that a TLS-tunnel really is in place if the used or available SASL mechanisms imply plain text transfer of challenge/response data. It is the sole responsibility of the applications to evaluate the circumstances. And remote-viewer indeed seems to take care ....

TLS was not really enforced by our settings ... so far

I am lazy and I use libvirt tools to start qemu-based VMs. The TLS configuration is, therefore, in a way a global one for all VMs. It activates (potential) TLS support for the Spice console whether the VM in the end really offers a special TLS-port or not. In this case the global configuration has no consequences in the sense of TLS enforcement; we must still define a VM-specific TLS-port to really enable TLS for a chosen VM. And as long as a standard network port is defined for the VM and opened on the KVM/Qemu-server the usage of TLS is not enforced. A good reason for remote-viewer to be careful with regard to SASL.

SASL RPMs

We have to install packages for SASL on the server and also on the client. Opensuse provides SASL in form of "cyrus-sasl". Required packages for our tests are:
cyrus-sasl, cyrus-sasl-digestmd5, cyrus-sasl-plain, cyrus-sasl-saslauthd, cyrus-sasl-scram, libgsasl-lang, libgsasl7, libsasl2-3, libsas2-3-32bit, perl-Authen-SASL.

Some of these packages provide specific SASL "mechanisms" for the exchange of challenge/response data.

Basic preparations for Qemu and SASL on the KVM/Qemu-server

In previous articles we learned that remote-viewer accesses the Spice console of a VM directly via Qemu (and not libvirt). So we must prepare the start of a qemu-process for our VM such that parameters enable the use of SASL. As with TLS we use the file "/etc/libvirt/qemu.conf" for the configuration. For our present purposes we activate the following options:

spice_tls = 1
...
spice_tls_x509_cert_dir = "/etc/pki/libvirt-spice"
...
spice_sasl = 1
...

You are already familiar with the TLS-related options. The only new point is the activation of SASL as the authentication mechanism for the Spice console. Folks who start qemu processes manually or with the help of scripts should read
https://www.spice-space.org/spice-user-manual.html
for the relevant options to add to the "/usr/bin/qemu-system-x86_64"-command. Spice related parameters may look similar to what I get in may case, namely

/usr/bin/qemu-system-x86_64 ..... -spice tls-port=20002,addr=0.0.0.0,sasl,disable-ticketing,x509-dir=/etc/pki/libvirt-spice,tls-channel=default,image-compression=auto_glz,seamless-migration=on ......

Note the location of the x509-directory; we got already acquainted with it it in the last article: It is used by qemu to read in TLS/SSL-certificates and key information which we must place there in advance, e.g for the CA and the server. If we started VMs directly with "qemu"-comands on a CLI we could change this directory individually for VMs. Using virt-manager or virsh forces us to define one x509 directory for all VMs, instead. Keep this in mind.

The commenting text in the file "/etc/libvirt/qemu.conf" tells you already that additional configuration steps are required in a file just below "/etc/sasl2/". This directory gathers SASL configuration files for various services that make use of SASL.

On a Leap 15.2 system no special default configuration file for "qemu" is provided at "/etc/sasl2/", but for "libvirt". For our present purposes we just copy the existing file "/etc/sasl2/libvirt.conf" to a new file "/etc/sasl2/qemu.conf". Why "qemu.conf"? Well, this is the instruction given in Opensuse's virtualization documentation - and it seems completely logical. This may lead you to the assumption that the "service" in question always has to be qualified as "qemu" in relation to SASL. We shall later see that this assumption is wrong when we invoke the "saslauthd"-daemon ...

For our first tests we activate the following two options, only, in the file "/etc/sasl2/qemu.conf" by un-commenting respective lines, out-commenting others and a minimum of editing:

mech_list:  plain scram-sha-256 
# mech_list:  plain scram-sha-256 digest-md5
..
sasldb_path: /var/spice/sasl/passwd.db
...

With the "mech_list" we obviously define a list of SASL mechanisms. We shall see how we specify which of these mechanism remote-viewer should use in a minute.

The mechanisms "plain" and "scram-sha-256" lead to an exchange of (salted) challenge/response data in clear text. They offer no real security for man-in-the-middle attacks in our Intranet. So, these mechanisms must be used in combination with a TLS tunnel, only. For possible attack-vectors see e.g.
https://tools.ietf.org/html/rfc7677
and
https://tools.ietf.org/html/rfc5802

The good message is: Remote-viewer will block the access to the Spice console of a VM if the connection is not secured by TLS/SSL!

Note the out-commented line with a crypto-mechanism specified in addition, namely "digest-md5". We shall use this line for tests of situations where a standard connection without TLS is established or might be established as a fallback. We shall see that remote-viewer will pick "digest-md5" automatically if TLS is not guaranteed and if the mechanism is available.

However, "digest-md5" must itself be regarded as insecure due to its weak cryptography. In a productive environment you should simply forget it - and best eliminate it from your configuration! Let remote-viewer check for sufficient TLS conditions - and let it refuse access to the target VM if necessary.

The parameter sasldb_path specifies the path to sasldb2-files which should contain the credentials. In my settings the reader recognizes the directory below which I placed a folder for a pure Unix socket in local access scenarios (the previous articles). You may, however, specify whatever directory you like on your system. But be aware of required access rights; see below.

How to fill sasldb2 with credentials? What access rights are required?

Some basic information about the usage of sasldb2-files is given e.g. at
https://blog.sys4.de/cyrus-sasl-sasldb-konfigurieren-de.html.

According to the test settings above we place our sasldb-files into a folder "/var/spice/sasl/" (see below). Before you blindly experiment with adding users, consider some hints regarding the entries:

SASL distinguishes between users of the same name for different systems or application environments. Users have to be qualified with a user-name and a realm in the form

username@realm

Regarding the "user":
It does not matter what usernames we choose; we can use fictitious users - they need not exist as valid users on the KVM/Qemu server (or the client-system) at all. However, as remote-viewer normally "suggests" the present username in a dialog for authentication (see below) it may be clever to add users with these suggested names - just to save some time with typing. In my test environment I work as user "myself" on the client "MyLAP", but sometimes also as user "uvmb" on the server "MySRV". So, I should have valid entries for both users.

Regarding the "realm":
For a simple sasldb you can basically define as a realm whatever you want - but the user who wants to authenticate has to know what to provide. So he/she should be able to associate it with some meaning, e.g. the VM's name. The "realm" is, unfortunately, NOT set or defined automatically later by the remote-viewer client and is in no way related to the contents of TLS certificates or target domain names presented during the authentication process. It can be freely set by the user in an SASL authentication dialog presented by remote-viewer: The user there can fill in anything after "username@...". To become authenticated, however, what he/she fills in must match an entry in the sasldb-file.

Thus, we could define a fantasy user "tom@waits" with a password "the-piano-has-been-drinking"; it would work - as long as the remote-viewer user has all this information and provides it properly in the authentication dialog.

There is, however, one more rule to keep in mind during your experiments:

If the user provides just a username without any realm in the SASL authentication dialog then the hostname will be added automatically on the server-side. And the hostname is the one in "/etc/hostname" on the server.

(The qemu-end of the SASL authentication does not seem to differentiate in cases where we use multiple IPs and different FQDN entries at a DNS server or in /etc/hosts for the host.)

In my test case the hostname is "myserv.anraconc.de". But be careful: You may have the short-name ("mysrv") standing in "/etc/hostname" on your Opensuse Leap 15.2 system! You should have a proper entry "myself@hostname" in your sasldb. If in doubt enter entries with both the short form and the FQDN of your KVM-host.

As root we now prepare a folder "/var/spice/sasl/" on the server (we have a folder "/var/spice/" already from previous efforts) and add some users with the help of the "saslpasswd2"-command :

mysrv:/var/spice # mkdir /var/spice/sasl
mysrv:/var/spice # chown root.qemu /var/spice/sasl
mysrv:/var/spice # chmod 750 /var/spice/sasl
mysrv:/var/spice # saslpasswd2  -a qemu myself@mysrv.anraconc.de -f /var/spice/sasl/passwd.db
Password: 
Again (for verification): 
mysrv:/var/spice # saslpasswd2  -a qemu myself -f /var/spice/sasl/passwd.db
...
mysrv:/var/spice # saslpasswd2  -a qemu uvmb@mysrv.anraconc.de -f /var/spice/sasl/passwd.db
...
mysrv:/var/spice # saslpasswd2  -a qemu uvmb -f /var/spice/sasl/passwd.db
...
mysrv:/var/spice # saslpasswd2  -a qemu xen -f /var/spice/sasl/passwd.db
...
mysrv:/var/spice # saslpasswd2  -a qemu xen@xensrv -f /var/spice/sasl/passwd.db
...

Afterward, you will find two new files in "/var/spice/sasl":

mysrv:/var/spice/sasl # la 
mysrv:/var/spice/sasl # la
total 28
drwxr-x--- 2 root qemu  4096 Apr 18 18:09 .
drwxr-xr-x 3 root root  4096 Apr 18 18:07 ..
-rw------- 1 root root    16 Apr 18 18:09 passwd.db.dir
-rw------- 1 root root 23384 Apr 18 18:09 passwd.db.pag
mysrv:/var/spice/sasl # 

Note the rights: The passwd-files can only be read by root. Why? Well, such a SASL file contains the credentials in clear text! It must be protected!

But, with these settings we would again run into a problem, which we have already seen in previous articles: The user of the qemu-processes is "qemu" on Leap 15.2-systems - at least when qemu-processes are started by libvirt-tools! This user "qemu" must be allowed to read critical files, in our present situation the "passwd.db"-files. Therefore, we change the group to "qemu" and the access rights to "640":

mysrv:/var/spice/sasl # chown root.qemu pass*
mysrv:/var/spice/sasl # chmod 640 pass*
mysrv:/var/spice/sasl # la
total 28
drwxr-x--- 2 root qemu  4096 Apr 18 18:09 .
drwxr-xr-x 3 root root  4096 Apr 18 18:07 ..
-rw-r----- 1 root qemu    16 Apr 18 18:09 passwd.db.dir
-rw-r----- 1 root qemu 16384 Apr 18 18:09 passwd.db.pag
mysrv:/var/spice/sasl # 

Warning: Please check that the qemu-group contains the user "qemu", ONLY !

To check which users are enlisted in our backend we use the command "sasldblistusers2".

mysrv:/var/spice/sasl # sasldblistusers2 -f /var/spice/sasl/passwd.db 
xen@xensrv: userPassword
xen@mysrv: userPassword
uvmb@mysrv: userPassword
uvmb@mysrv.anraconc.de: userPassword
myself@mysrv: userPassword
myself@mysrv.anraconc.de: userPassword
mysrv:/var/spice/sasl # 

You see that users provided without a system realm automatically got the present system's name attached!

If we wanted to delete a user we would use:

mysrv:/var/spice/sasl # saslpasswd2  -d xen@xen -f /var/spice/sasl/passwd.db
mysrv:/var/spice/sasl # sasldblistusers2 -f /var/spice/sasl/passwd.db 
xen@mysrv: userPassword
uvmb@mysrv: userPassword
uvmb@mysrv.anraconc.de: userPassword
myself@mysrv: userPassword
myself@mysrv.anraconc.de: userPassword
mysrv:/var/spice/sasl # 

For tests you should vary the passwords of usernames defined for different systems.

Indications of basic security problems

As long as a standard TCP port is defined for Spice fallback-situations may occur without any announcement. But remote-viewer checks whether the tunnel really is TLS secured or not. If not, it will automatically try to choose a SASL mechanism with encryption - as e.g. digest-md5 - if such a mechanism is available to the qemu-process on the server. If such a mechanism is not available remote-viewer will block the access to the Spice console:

A typical indication that something is wrong is a decline to enter a username in the dialog window for authentication opened by remote-viewer.

Problematic SASL mechanisms of course are PLAIN and all SCRAM-mechanisms. A noteworthy fact about remote-viewer is:

remote-viewer will try to use a SASL mechanism with encryption even if you have explicitly specified something else!

Problematic situation arise for a remote-viewer command (executed locally or on a real remote client) which contains the specification of a standard non-TLS port and a TLS-port - e.g.:

remote-viewer spice://myserv.anraconc.de:20001?tls-port=20002

for a VM with a Spice configuration that includes a standard non-TLS port and "defaultMode" set to "insecure" or "any". The same is true for:

remote-viewer spice://myserv.anraconc.de:20001?tls-port=20002&sasl=plain

If remote-viewer in its background dialog with the server does not find a "worthy" mechanism it will give you an error hint:

Failed to start SASL negotiation: -4 (SASL(-4): no mechanism available: No worthy mechs found)

Spice configuration to be used with plain text SASL mechanisms

To be on the safe side we configure Spice in the XML-definition file for a VM as follows:

   <graphics type='spice' tlsPort='20002' autoport='no' listen='0.0.0.0' keymap='de' defaultMode='secure' >
      <listen type='address' address='0.0.0.0'/>
      <image compression='auto_glz'/>
      <gl enable='no'/>
    </graphics>

The difference in comparison to specifications in previous articles is that we do not specify a standard "port" at all - but still have "autoport='no'" in place AND set "defaultMode='secure'".

How do we specify a SASL mechanism when starting remote-viewer?

The general form is as simple as this

remote-viewer spice://FQDN??tls-port=NR_OF_TLS_PORT&sasl=MECHANISM

where "FQDN" refers to the address of the server, "NR_OF_TLS_PORT" to the tlsPort settings for Spice in the VM's configuration and "MECHANISM" to one of the SASL mechanisms in the list of the "/etc/sasl2/qemu.config"-file.

Remote test

We are confident and test our present settings. We restart libvirtd on the server. A privileged user "uvma" starts the test VM there for us. Then we login into the remote system - in my case as user "myself" into "MyLAP". On a terminal we enter:

myself@mylap:~> remote-viewer spice://mysrv.anraconc.de?tls-port=20002&sasl=plain

We then get an authentication dialog:

We enter the password defined in the credentials file - in my case for "myself@mysrv.anraconc.de" and not for "myself@mysrv" (!!) - and there we go:

After a login we can work with the desktop of the VM as described in previous articles and open up more screens.

Tests for realm dependence of the authentication

We are now able to test the dependency of the authentication on the "realm"; we just type in the "username@realm" which we want to test and provide the related password. Try also cases without providing a "realm". I leave it to you to perform such tests.

Afterward it should be clear that the FQDN shown in the authentication dialog is important for the validity of the TLS server certificate - but it has nothing to do with the SASL realms!

A dis-functionality: Freezing Spice windows if the Spice session is taken by another user

Now you could try to do the same shortly after and locally on the server "mysrv" - i.e. you try to steal the "seat" in front of the Spice console. In previous articles we have seen that the Spice windows of the user, from which the seat was taken, were just closed without any warning. This was not the case on my systems with TLS and SASL. Instead and unfortunately the Spice window of the original user froze; he/she could not enter anything anymore. One could not even close it explicitly without killing the job.

Otherwise the handling of an active Spice session is as we are used to.

What do we get for situations with TLS not fully enforced?

Just for testing purposes we change the security situation by adding a standard port to the Spice configuration and set the defaultMode in the VM's XML-configuration to 'any':

   <graphics type='spice' port='20001' tlsPort='20002' autoport='no' listen='0.0.0.0' keymap='de' defaultMode='any' >
      ...
    </graphics>

Then a dubious situation as provoked by

myself@mylap:~> remote-viewer spice://mysrv.anraconc.de:20001?tls-port=20002&sasl=plain

The TLS-option is ignored in this case and this in turn leads to a decline to enter a user@realm in the first field of the dialog:

accompanied by a warning on the terminal window :

(remote-viewer:21318): GSpice-CRITICAL **: 17:33:36.750: Failed to start SASL negotiation: -4 (SASL(-4): no mechanism available: No worthy mechs found)

However, if you now change the "mech_list" for SASL in "/etc/sasl2/qemu.config" such that it includes "digest-md5", then

myself@mylap:~> remote-viewer spice://mysrv.anraconc.de:20001?tls-port=20002

would work. And also - somewhat unexpected - the following works:

myself@mylap:~> remote-viewer spice://mysrv.anraconc.de:20001?tls-port=20002&sasl=plain

Wireshark, however, reveals that the specified sasl-mechanism is ignored and digest-md5 is taken in this case:

Well, this is a bit confusing as remote-viewer does not inform the user about the measures taken. My advice is to prepare for clarity: If you want to work with SASL then disable the standard non-TLS port for Spice and do not include weak SASL crypto-mechanisms in the mech-list at all. It is better that remote-viewer stops the conversation ....

Failure for local access to the Spice console from virt-manager

There is a problem with our qemu-setting that enforces SASL and virt-manager. Afterwards we can no longer access the Spice console locally on the KVM/Qemu-server with the built-in Spice client of virt-manager. We get a screen that wants a password from us - but no user and realm:

You can fill in whatever you want of known passwords for root, qemu and other users which you may have filled in into your sasldb. (You could have added an entry for "root@mysrv.anraconc.de" with some password, because virt-manager runs with user root). It is not going to work.

There seems to be a basic problem; we get a log message as

  
2021-04-30T17:05:20.745776Z qemu-system-x86_64: warning: Spice: red-stream.c:1039:red_sasl_start_auth: sasl context setup failed -7 (invalid parameter supplied)

The funny thing is that another libvirt-dependent tool, namely "virt-viewer" works correctly with SASL. You can test it locally on the KVM/Qemu-server, e.g. for the following situation:

  • Allow for a standard Spice port without TLS (in our test case 20001; in our series we have not yet come to the point where we use libvirt-tools remotely together with TLS 🙂 ).
  • Let Spice listen on all on all network devices (including 127.0.0.1).
  • Activate SASL for qemu (via settings in "/etc/libvirt/qemu.conf"; see above).
  • Allow for a SASL mechanism with encryption.

If you then enter e.g. the command

mysrv:~ # virt-viewer -c qemu:///system

(e.g. as user root) an authentication dialog opens, where we can fill in a username ("root" is suggested) plus a realm, if we want, and a valid password for the combination.

Enter a valid password for some entry (e.g. for root@mysrv.anraconc.de") in the sasldb and the Spice console comes up as usual. So - there is some dis-functionality in virt-viewer, when SASL is activated for qemu (and not a libvirt port or local libvirt Unix socket).

Switching to the saslauthd daemon

"/etc/sasl2/qemu.config" was copied from a libvirt-oriented file. We can, of course, specify other SASL rules for the service "qemu". In particular we can invoke a "saslauthd" daemon. We achieve this by changing the settings in "/etc/sasl2/qemu.config" to:

mech_list:  plain scram-sha-256
pwcheck_method: saslauthd

Please out-comment other lines. Why did I only specify clear text mechanisms? Well, saslauthd simply does not work with crypto-mechanisms! It is not designed for it. It is invoked locally on our KVM server where it listens on a Unix socket after having been started:

mysrv:~ # netstat -ax | grep sasl
unix  2      [ ACC ]     STREAM     LISTENING     603842   /run/sasl2//mux

To get that far there are a few more things to do, of course: We must configure saslauthd and start the related service. The basic configuration of "saslauthd" on a Leap 15.2 system is done via settings in the file "/etc/sysconfig/saslauthd".

For a simple scenario, which uses the standard PAM mechanisms on the server, we can leave the default settings there as they are:

SASLAUTHD_AUTHMECH=pam
SASLAUTHD_THREADS=5
SASLAUTHD_PARAMS=""

What is the expected effect? Well, afterward, we should be able to authenticate ourselves with credentials (usernames and passwords) already defined for valid accounts on the server (e.g. in "/etc/passwd" and "/etc/shadow"). Note:

No login shell is required for our special Spice users!

So, we can create some (harmless) user accounts on the server to test the Spice/SASL authentication (with some preset complicated passwords).

Before testing we should not forget to start the daemon by "systemctl start saslauthd" or "rcsaslauthd start". But before we do this there is one more step required ....

PAM configuration to support authentication for Spice by saslauthd

PAM works for services - and what PAM should do for a service has to be defined. The configuration files are placed in "/etc/pam.d/". Naively, I had expected that we would need a "qemu" configuration file there. Well this is wrong. I could see it from resulting error messages in "/var/log/messages"

... saslauthd[25571]:                 : auth failure: [user=myself] [service=spice] [realm=] [mech=pam] [reason=PAM auth error]

The "service" to be configured is "spice" ! Ok, the machine gets what it wants. I created a simple file "/etc/pam.d/spice" with the following standard contents:

#%PAM-1.0
auth     requisite      pam_nologin.so
auth     include        common-auth
account  include        common-account
password include        common-password
session  required       pam_loginuid.so
session  include        common-session

This is enough to support our SASL operations; some lines as e.g. for the password could even have been omitted for our present objectives. Note hat a "realm" does not make much sense if we work with a local PAM for Linux password files on a Linux host, only, and no external backend.

Test of salsauthd

Stop your VM if it were running. Restart libvirtd, start saslauthd, start the VM.
You can pre-test your saslauthd configuration for the service "spice" with existing user accounts on the server with the command

mysrv:~ # testsaslauthd  -s spice -u uvmb -p ******** 
0: OK "Success."

You must of course replace "uvmb" without a username defined on your server and the "******" with the related password. .

Now you can try it for a remote-viewer session. The same authentication dialog we got before for our sasldb-experiment should appear. You then only enter a username (no realm) into the filed for the username. Should work without any problems.

Major deficits of the SASL-authentication for remote-viewer

During his/her tests of the authentication with sasldb2 the reader has certainly realized the following point:

Any valid combination of a username, a related realm and a password authorizes us to get access to the Spice console of our test-VM.

There is no unique relation between a UID on the remote-client or on the server and the "username@realm" combination. And there is no real relation of a username/user with a specific VM. Therefore, the situation is actually worse:

A user providing a valid "username@realm" (existing in sasldb2) has access to the Spice consoles of all VMs running on the server!

Activating SASL in the general way we did it for the startup of all qemu-processes establishes an authentication and authorization mechanism for the Spice consoles of all VMs on a KVM server - if the user knows the relevant TLS-ports or just checks out ports systematically.

Obviously, the logic for our present setup is that we authenticate a general Spice user via SASL on the server. We cannot establish a relation between the Spice related SASL "username@realm" and a specific VM. The present version of remote-viewer does not provide other data (as an rhost) which we could e.g. use in some cleverly crafted PAM rules for special modules. (You can see the information provided from log-entries for your VM and wrong authentications)

In my opinion an authorization should be specific for a user (or a group of selected users) and a specific target service. And it should be such that the server alone can control the service access. For a bunch of VMs on the KVM/Qemu-server we would assume that we could establish a specific user authentication for the Spice console of a specific VM and no other VMs.

So, it is very unfortunate that "realm" delivered by remote-viewer can freely be set by the user and that it is independent of the TLS parameters and/or data of the remote-host. Thus, there is no way to force the user on the client-system to enter a VM-specific user@realm combination. And any other user sharing one valid username/password combination known to him opens up access to all Spice consoles for other users - if no additional measures were taken.

If you wonder how a coupling of certificate data to the realm would have helped: We could have achieved a relation between a realm and a VM, if we had coupled the VM to a sub-domain for a wildcard certificate on the server and to a specific IP on the server - and if the realm were taken from the "common name" (i.e. the FQDN) in the certificate. Then we had just needed a specific username@ realm entry in the sasldb - and we would have gotten a VM-specific authentication. In the case of saslauthd the delivery of information about the remote host would have helped. I leave it to the user to figure that out. Its fruitless thinking anyway, ...

Actually, setting a password int VM's XML file would have given us a VM-specific authentication. Unfortunately, we are not allowed to combine the setting of a VM-specific password in the XML-file in addition to SASL-authentication. The VM can not be started by virt-manager or virsh then. So, it is a bit of a mess with SASL and remote-viewer ...

Are there valid counter arguments?
Well, you could argue that we could hinder access to specific VMs by blocking ports on the server for certain client-systems. Well, and what for situations where multiple users are allowed to login to any client-machine in an office?
And you could argue: But the user has certainly to login into the VM as well? Yeah, but there is the problem with Spice - if someone legitimately had already opened a a session on the VM via a Spice console this session could be taken from him/her in the present open status by an other user authenticated via SASL for some other entry in the sasldb. Security is something else ...

Conclusion

To activate SASL for some general authentication to get access to the Spice console of a chosen VM is simple. However, the SASL authentication does not allow us

  • to restrict the access to the Spice console of a specific VM to a specific username@realm combination.
  • to restrict the access to the Spice console to a specific UID on either the remote client or the KVM-server.

So, TLS in combination with SASL is to a certain degree a disappointment. A VM-specific password has more advantages. Note, that for present versions of "qemu" it is not displayed anymore in the output of "ps aux | grep qemu".

The combination of TLS and SASL with remote-viewer is not really useful for situations where we want Intranet users to work with VMs via Spice sessions - each of them with a (user-) specific VM or some (user-) specific VMs, only.

If you wanted to make Spice sessions available to a selected user only for specific VMs we thus end up with the question: How can we become more restrictive?

In the next article

KVM/Qemu VMs with a multi-screen Spice console – VIII – VM and user specific restrictions for remote-viewer connections – iptables and sudo

I will therefore discuss the application of user specific iptables- and sudo-rules on remote client-systems. Not ideal - but a step forward.

Mail-server-upgrade to Opensuse Leap 15 – and some hours with authentication trouble …

Some of my readers know that the mail server in my private LAN resides in an encrypted KVM/qemu guest. It provides IMAP- and SMTP-services to mail-clients - and receives emails from several hosted servers on the Internet via a fetchmail system in a DMZ. It was/is my policy that any access to a mail service account on my private mail server requires authentication against user entries on a separate LDAP-server. The accounts the IMAP/SMTP-service-daemons deal with are not to be confused with Linux user accounts: On the mail server NO Linux user accounts are required for mail handling. I regard the absence of standard Linux user accounts on the mail-server as a small, but effective contribution to security. No mail user can login into the mail server as a Linux user. Nevertheless authentication for the use of mail services is required.

Upgrade top Leap 15 resulted in unusable mail services

The manual upgrade of the mail server system from OS Leap 42.3 to Leap 15 seemed to work perfectly. I got no serious warnings. As root I could login to the virtual KVM guest via ssh - and systemd had started all required services: Fetchmail operated on external servers in the DMZ and transferred new mails to the upgraded mail server. There my postfix queues and secondary services for virus and spam checks seemed to work perfectly. Regarding IMAP I could also see that new entries for new mails appeared in various email accounts (more precisely: in related spool directories). Everything looked great ...

However, the big surprise came pretty soon: No mail user could login to the IMAP-service - neither with Kmail, nor Mutt, nor Thunderbird. Access to the SMTP service for sending email was not possible either. System messages appeared on the GUIs saying that there was an authentication error. A very unpleasant situation which required analysis ....

In the meantime I had to start a backup copy of the old mailserver guest installation. On this front
virtualization proved its strengths and simplicity - I had made a copy of the whole KVM guest before the upgrade and just had to include the copy as a virtualization domain into the KVM setup of the virtualization host. But, as the upgraded server had already processed some new mails, I needed to transfer these mails between the servers and reconstruct and reindex some IMAP accounts ... A simple, but a task which can be done by some scripts ....

Error analysis

It took me quite a while to figure out where the origin of the upgrade problem was located. I first checked my local firewall protocols both on the mail server and on the LDAP server. Nothing special there ... Then I checked the LDAP access protocols - there were successful data requests from various systems - but astonishingly not from the mail server. So it seemed that the mail services did not even try to authenticate their users ... strange ....
I then created a new IMAP test user based on a new local Linux user account, i.e. with an entry in "/etc/passwd" and "/etc/shadow". Guess what? This user could work without any problems. So, obviously the communication of the mail services with the LDAP service for authentication was not triggered or failed in a strange way. I, therefore, tried a manual data request to the LDAP server from the mail server - and got a perfect answer. So, there seemed to be no fundamental problem with the required sssd-daemon and client-configurations. What else was wrong? A bit of despair was in the air ...

The role of PAM in the game

Then I tried to remember what I had done in the past to separate the email accounts from the Linux user accounts. Over the last years I had actually forgotten how I had treated this problem. After some reading in old diaries my attention eventually turned to PAM ...

The PAM-layer offers Linux admins the possibility of fine-tuning access/authentication conditions for the usage of a service; among other things you can request certain PAM-modules to authenticate a user via given credentials against defined resources. A sequential series of required, sufficient or optional criteria can be set up. ( When a service needs additional Linux user account information during a session NSS can in addition request information from name resolution backends as "/etc/passwd". However, this is NOT required for mail services. )

Linux mail services often use the SASL-framework and the saslauthd daemon to perform authentication. SASL can communicate with a variety of authentication backends directly - but it can also use PAM as an intermediate layer. And, in fact, I had used PAM to access my independent LDAP-server with mail account credentials via the PAM-module for SSSD.

I have described my simple approach in a previous article
https://linux-blog.anracom.com/2014/03/15/cyrus-imap-mit-sasl-pam-sssd-und-ldap-opensuse-12-313-1-ii/
Unfortunately, only in German. I, therefore, summarize the basic ideas shortly (see also the graphics in the referenced article).

The things one has to do to force IMAP and/or a SMTP services to use LDAP, but other services to use local authentication resources is:

  • We direct local login-services, ssh-services, etc. on the server via PAM to local resources, only.
  • We eliminate any UIDs corresponding to email account names from local resources as "/etc/passwd" and "/etc/shadow" (and NIS if used).
  • We do not create any local home-directories for email account names.
  • We eliminate LDAP as a usable NSS resource from nsswitch.conf; i.e. we eliminate all LDAP references there.
  • We setup special PAM files in "/etc/pam.d" for the IMAP-service and the SMTP-service. These files will necessarily include pam-modules for the "sss"-service (pam_sss.so).
  • We select entries on the LDAP server for users which for any reasons shall NOT or NO LONGER get access to the mail service accounts, set the "host"-attribute for these entries and configure sssd to use the host-attribute. Or deny certain user names access to the IMAP-service by the help of IMAP -configuration files; cyrus e.g offers the maintenance of a list "userdeny_db".

This strategy worked very conveniently already on an Opensuse 12.3 platform. Examples for the required special files "/etc/pam.d/imap" and "/etc/pam.d/smtp" are given in the article named above. The mix and sequence of the statements there is due to the fact that locally defined system users as "cyrus" must get access to the IMAP-service, too.

What had happened during the Leap 15 upgrade?

My configuration had survived multiple upgrades of the virtualized server in the past. But not the one to Leap 15! What had happened?

After having remembered the importance of the PAM configuration, I eventually had a look into the directory "/etc/pam.d" on the upgraded system and compared it to the respective directory on the original system. Whereas during previous upgrades "personal" PAM configuration files for services had been respected, the upgrade to Leap 15 simply had removed my PAM configuration files for SMTP and IMAP - without a backup! Incredible, but true! Actually and astonishingly, the contents of some other standard PAM files had been transferred to a backup ....

A restoration of my PAM files for the mail services lead to an immediate success - authentication for the access of mail accounts on the upgraded server was possible again. Some hours in the hell for Linux admins came to an end.

Conclusion

Never (!) trust a standard upgrade of a whole Linux system procedure to keep configuration files in "/etc/pam.d" untouched. Keep an admin or system diary for unusual approaches. And - of course: Full backups of critical systems before backups are a MUST ....