[Libvir] PATCH: RFC supporting SASL authentication
by Daniel P. Berrange
History: we currently provide two TCP sockets, one clear text, no auth,
the other TLS with x509 client certificate verification for auth. We
also provide a UNIX domain socket relying on file perms to restrict access.
I have previously provided a policykit patch for the latter allowing admin
defined auth policy for UNIX socket access.
The PolicyKit patch was flawed in that it did not provide a way for a client
app to determine whether the UNIX socket needed PolicyKit auth ahead of time
or not. This required apps to make assumptions prior to connecting which
is not really viable.
This mail is working towards a more flexible authentication solution, and
goes straight for the big picture by integrating SASL authentication. This
gives us integration with Kerberos (GSSAPI) and PAM and whatever the hell
else SAS supports[1].
The critical decision in all this is the wire protocol & how to adapt it
to slot in authentication in a way that is compatible with existing clients.
As it stands the decision to use clear data vs TLS on the wire is based on
the socket the client connects to - we do a TLS handshake at the very start.
We need to be able to support SASL on all sockets, TCP, TLS & UNIX since
they can all benefit from stuff like Kerberos. So I decided we need to
integrate at the RPC layer for this to work.
The general protocol picture
----------------------------
It helps to look at qemud/remote_protocol.x when reading this next ...
Every API basically has an RPC call & reply pair. The reply messages have
a status field, either 'REMOTE_OK' or 'REMOTE_ERROR'. In the former case
the normal API return values follow on the wire. In the latter case a
virErrroPtr object is serialized on the wire.
For this patch I decided to add a 3rd code, REMOTE_AUTH. If an application
tries to make an RPC call on a socket requiring authentication, and has not
yet authenticated the server will return REMOTE_AUTH code. It then also returns
an int (remote_auth_type) specifying the authentication method to use. I have
defined two:
enum remote_auth_type {
REMOTE_AUTH_NONE = 0,
REMOTE_AUTH_SASL = 1
};
With plans to add REMOTE_AUTH_POLKIT in a future patch.
A legacy client getting back REMOTE_AUTH code will just quit the connection
attempt since they don't support authentication. If the admin so desires
they can still provide the TLS socket in a non-authenticated mode and only
turn on SASL for the TCP socket. So the decision about whether to enable
legacy clients is admin controlled. This is the best we can do.
A new client getting back REMOTE_AUTH code will then read the remote_auth_type
off the wire. If the requested type is one that the client supports then it
can begin the authentication process, otherwise we virRaiseError and stop
connecting.
The SASL specific picture
-------------------------
For the SASL auth the process involves a multi-phase handshake looking
something like:
client server
1. -> ask for mechanism list -> new ctx
2. new ctx <- list of mechanisms <-
3. start auth -> initial auth data -> start auth
4. step auth <- reply auth data <-
5. -> step auth data -> step auth
goto 4. <- reply auth data <-
Authentication can complete at step 4 in this process, or steps 4 & 5
can repeat an arbitrary number of times.
So, to implement this if it neccessary to define 3 new RPC calls internal
to the remote driver/daemon (aka not exposed to public API like the rest
of the RPC calls). These are:
REMOTE_PROC_AUTH_SASL_INIT = 66,
REMOTE_PROC_AUTH_SASL_START = 67,
REMOTE_PROC_AUTH_SASL_STEP = 68
These are basically just punting back & forth the data going in & out of
the appropriate SASL apis. sasl_{server,client}_{new,start,step} See
the man pages for more info.
So on the server end, if a socket is configured to require SASL auth, the
server will reject all RPC calls *except* for those three above with the
REMOTE_AUTH code. Once SASL auth has completed, it will allow all the
normal RPC calls. The effect is basically that the client is not able to
call virConnectOpen & friends until auth has completed.
On the client end, the fun is in the 'call' method of remote_internal.c.
This has been split in two. The original method is now 'onecall', and there
is a thin wrapper named 'call'. 'call' simply invokves onecall, and if it
gets back a REMOTE_AUTH code, will do the SASL handshake & then re-run the
original call. So again the effect is basically that the first virConnectOpen
will cause the auth handshake to be performed.
The SASL implementation details
-------------------------------
This is the bare minimum SASL integration. I have not attempted to hook
up any callbacks for gathering credentials. This basically means that the
only SASL mechanism which works is Kerberos GSSAPI - its credentials are
fetched out-of-band & so don't require callbacks. We do need to consider
callbacks later so we can do username/password auth, and all the various
other methods SASL has.
As well as authentication, some SASL mechanisms provide a way to negotiate
a data encryption layer for the subsequent session. GSSAPI is the only
commonly used mechanism which supports this. I have not implemented this
yet though. What we would do though is to enable this capability on the
the plain TCP socket only. This would make the TCP socket truely secure,
and avoid any extra overhead on the TLS socket or UNIX domain socket.
I have set the wire packet size for the SASL negotiation to 8192 bytes at
a time. This has been sufficient so far, but I need to validate this
before we commit, because this will be wire ABI sensitive. Or I could
change the XDR spec to be variable length. Anyway needs re-visiting
This only deals with authentication. I have not attempted any authoriztion
controls. So anyone who has a valid kerberos principle can connect to the
server. We clearly need a local group list as we do for the x509 client
certificates. Ultimately we could try LDAP lookups & other intersting
suggestions.
The SASL stuff is detected in configure & enabled/disabled as appropriate.
I need to add extra config file params though to let the sysadmin control
what socket uses what auth mechanism.
The setup / usage details
-------------------------
As I said, I only used GSSAPI so far. To use this all your clients need to
be able to kinit & get a ticket. For testing I have setup my own personal
Kerberos server using Fedora 7 & FreeIPA (http://freeipa.org/). Each libvirt
server needs to be issued with a Kerberos service principle. I am using the
word 'libvirt' as the service name. The service principle must match the
FQDN of the server host. So on your Kerberos server you can issue a service
principle with
kadmin.local
> addprinc libvirt/cherry.virt.boston.redhat.com(a)VIRT.BOSTON.REDHAT.COM
> ktadd -k /tmp/cherry-libvirt.tab libvirt/cherry.virt.boston.redhat.com(a)VIRT.BOSTON.REDHAT.COM
> quit
Then copy the /tmp/cherry-libvirt.tab file to /etc/libvirt/krb5.tab on the
server in question. (Change the hostnames & REALM as needed of course).
If you want to change the GSSAPI mechanism, the settings are in the file
/etc/sasl2/libvirt.conf. Though again only GSSAPI works so far.
If you edit the /etc/libvirt/libvirtd.conf file you can enable listen_tcp=1
and run run libvirtd --listen.
>From the client machine it should now be possible to do
$ kinit berrange(a)VIRT.BOSTON.REDHAT.COM
$ virsh --connect xen+tcp://cherry.virt.boston.redhat.com/
You probably screwed something up though along the way because Kerberos
is nasty like that. If you use --verbose with libvirtd it'll show details
of any errors during authentication. On the client end you can add in
a param on the connect URI of ?debug=stderr and it'll print some info
about the auth process to stderr. Check that it shows 'GSSAPI' as a
valid mechanism. If it doesn't, then your server is not configured as it
should be - check keytab file - check you have cyrus-sasl-gssapi RPM.
If that's ok, then check 'klist' on the client - if the first phase of
chatter between the client & the KDC worked you should see the principle
of the server cached on the client. If you don't, then check the KDC logs
in /var/log/krb5kdc.log
Kerberos/GSSAPI error reporting sucks really bad. That said, I'm sure
I'm missing something, because the errors I get out of SASL are even worse
than normal.
BTW, you can see various 'XXX' in my patch. Basically all of them need to
be addressed before I'd consider this patch suitable to merge.
configure.in | 39 +++
include/libvirt/virterror.h | 1
libvirt.spec.in | 3
qemud/Makefile.am | 21 +-
qemud/internal.h | 8
qemud/libvirtd.init.in | 3
qemud/libvirtd.sysconf | 3
qemud/qemud.c | 29 ++
qemud/remote.c | 370 ++++++++++++++++++++++++++++++++++--
qemud/remote_dispatch_localvars.h | 5
qemud/remote_dispatch_proc_switch.h | 24 ++
qemud/remote_dispatch_prototypes.h | 3
qemud/remote_protocol.c | 164 +++++++++++++++
qemud/remote_protocol.h | 59 +++++
qemud/remote_protocol.x | 53 ++++-
src/Makefile.am | 3
src/remote_internal.c | 307 +++++++++++++++++++++++++++++
src/virsh.c | 4
src/virterror.c | 6
tests/Makefile.am | 2
20 files changed, 1073 insertions(+), 34 deletions(-)
Regards,
Dan.
[1] Not entirely true. Some auth methods require credentials to be fetched
from the user, so we can only support methods for which we have callbacks.
This patch ignores the callback question, so only support GSSAPI where
the credentials are fetched out-of-band. This can be addressed later.
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules: http://search.cpan.org/~danberr/ -=|
|=- Projects: http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
17 years, 1 month
Re: [Libvir] Problem to compile virt-manager in debian etch
by Richard W.M. Jones
Marco Sinhoreli wrote:
> The autogen.sh output:
>
> ./autogen.sh
> libtoolize: `config.guess' exists: use `--force' to overwrite
> libtoolize: `config.sub' exists: use `--force' to overwrite
> libtoolize: `ltmain.sh' exists: use `--force' to overwrite
> hecking for a BSD-compatible install... /usr/bin/install -c
> checking whether build environment is sane... yes
> checking for a thread-safe mkdir -p... /bin/mkdir -p
> checking for gawk... no
> checking for mawk... mawk
> [...]
>
> The remaining seems okay.
So looks like it's working then?
Rich.
--
Emerging Technologies, Red Hat - http://et.redhat.com/~rjones/
Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod
Street, Windsor, Berkshire, SL4 1TE, United Kingdom. Registered in
England and Wales under Company Registration No. 03798903
17 years, 1 month
[Libvir] storage API and ZFS
by John Levon
Accidentally deleted your reply Richard, sorry.
ZFS 'pools' are aggregates composed of some number of real devices. LVM
confuses me so I don't know what they map on to, but the basic idea is
that you can carve filesystems out of such pools at will.
You can also carve out 'volumes' - these appear as a disk device in
/dev/zvol/dsk/poolname/volumename
It's the latter that you use in Xen to hold domU root filesystems (or
you can use a normal file on whatever file system, or a real device, as
desired).
What might be tricky is anything that claims to return "space left",
depending exactly on what you want it to mean. But (I think) certain LVM
setups have similar issues.
regards
john
17 years, 1 month
[Libvir] Is it possible to add an interface to intercept the migration process?
by Meng Ran
Hi All,
I'm thinking about if it possible to add an interface to let user
specified action to happen on destination during the migration, this
should be useful for migrating things that have different paths on
source and destination.
Allowing specified action(callback) to happen at a time point, e.g.,
after the config file is transfered and before starting the vm, can
bring in a lot of flexibilities considering the migration of devices
which are shared but have different paths/views. Giving the dest a
chance to recognize these devices and update the config, and then start
the vm probably is helpful there.
Comment?
Thanks,
Jack
17 years, 1 month
[Libvir] CPU pinning of domains at creation time
by Daniel Veillard
There are a few things I gathered on this issue. This affects
NUMA setups, where basically if a domain must be placed on a given cell
it is not good to let the hypervisor place it first with its own heuristics
and then later migrate it to a different set of CPU, but better to
instruct the hypervisor to start said domain on the given set.
- For Xen it is possible to instruct the hypervisor by passing
(cpus '2,3') in the SExpr where the argument is a list of
the physical processors allowed
- For KVM I think the standard way would be to select the
cpuset using sched_setaffinity() between the fork of the
current process and the exec of the qemu process
- there is no need (from a NUMA perspective) to do fine grained
allocation at that point, as long as the domain can be restricted
to a given cell at startup, then if needed virDomainPinVcpu() can be
used later to do more precise pinning in order to try to optimize
placement
- to be able to instruct the hypervisor at creation time adding the
information in the domain XML description looks the more natural way
(another option would be to force to use virDomainDefineXML, add a
call using the resulting virDomainPtr to define the set, and
then virDomainCreate would be used to do the actual start)
+ the good point of having this embedded in the XML is that
we still have all informations about the domain settings in
the XML, if we want to restart it later
+ the bad point is that we need to fetch and carry this extra
information when doing XML dumps to not loose it for example
when manipulating the domain to add or remove devices
- extracting a cpuset can still be an heavy operation, for example
if using xend on need one RPC per vcpu in the domain, the cpuset
being constructed by OR'ing logically all cpumaps used by the
vcpus of the domain (though in most case this will be the full
map after the first CPU and can be stopped immediately)
- for the mapping at the XML level I suggest to use a simple extension
to the <vcpu>n</vcpu> and extend it to
<vcpu cpuset='2,3'>n</vcpu>
with a limited syntax which is just the comma separated list of
allowed CPU numbers (if the code actually detects such a cpuset is
in effect i.e. in general this won't be added).
Internally implementing this should not be too hard, I would probably refactor
some of the existing parsing code, provide functions to get the cpuset and
the number of physical processors.
Does this sounds okay ?
Daniel
--
Red Hat Virtualization group http://redhat.com/virtualization/
Daniel Veillard | virtualization library http://libvirt.org/
veillard(a)redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/
http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/
17 years, 1 month
[Libvir] Problem to compile virt-manager in debian etch
by Marco Sinhoreli
Hello all,
I have a problem to compile the virt-manager in a Debian etch (64 bit
version). I got the virt-manager source from mercurial repository.
Bellow the output autogen.sh command:
./autogen.sh
libtoolize: `config.guess' exists: use `--force' to overwrite
libtoolize: `config.sub' exists: use `--force' to overwrite
libtoolize: `ltmain.sh' exists: use `--force' to overwrite
configure.ac:7: required file `./config.rpath' not found
man/Makefile.am:6: `%'-style pattern rules are a GNU make extension
pixmaps/Makefile.am:3: wildcard $(srcdir: non-POSIX variable name
pixmaps/Makefile.am:3: (probably a GNU make extension)
src/Makefile.am:15: wildcard $(srcdir: non-POSIX variable name
src/Makefile.am:15: (probably a GNU make extension)
src/Makefile.am:35: `%'-style pattern rules are a GNU make extension
src/Makefile.am:38: `%'-style pattern rules are a GNU make extension
src/Makefile.am:41: `%'-style pattern rules are a GNU make extension
src/Makefile.am:44: `%'-style pattern rules are a GNU make extension
src/Makefile.am:26: variable `schema_SOURCES' is defined but no program or
src/Makefile.am:26: library has `schema' as canonic name (possible typo)
src/Makefile.am:11: variable `libexec_SOURCES' is defined but no program or
src/Makefile.am:11: library has `libexec' as canonic name (possible typo)
src/Makefile.am:4: variable `bin_SOURCES' is defined but no program or
src/Makefile.am:4: library has `bin' as canonic name (possible typo)
src/Makefile.am:18: variable `desktop_SOURCES' is defined but no program or
src/Makefile.am:18: library has `desktop' as canonic name (possible typo)
src/Makefile.am:8: variable `python_SOURCES' is defined but no program or
src/Makefile.am:8: library has `python' as canonic name (possible typo)
src/Makefile.am:22: variable `dbus_SOURCES' is defined but no program or
src/Makefile.am:22: library has `dbus' as canonic name (possible typo)
src/graphWidgets/Makefile.am:5: `:='-style assignments are not portable
src/graphWidgets/Makefile.am:5: shell pkg-config --variable=codegendir
pygtk-2.0: non-POSIX variable name
src/graphWidgets/Makefile.am:5: (probably a GNU make extension)
src/graphWidgets/Makefile.am:6: `:='-style assignments are not portable
src/graphWidgets/Makefile.am:6: shell pkg-config --variable=defsdir
pygtk-2.0: non-POSIX variable name
src/graphWidgets/Makefile.am:6: (probably a GNU make extension)
src/virtManager/Makefile.am:3: wildcard $(srcdir: non-POSIX variable name
src/virtManager/Makefile.am:3: (probably a GNU make extension)
src/virtManager/Makefile.am:7: python_DATA:$(srcdir: non-POSIX variable name
src/virtManager/Makefile.am:15: `%'-style pattern rules are a GNU make extension
Any idea?
regards.
--
Marco Sinhoreli
17 years, 1 month
[Libvir] PATCH: Remote protocol receive+dispatch cleanup
by Daniel P. Berrange
Dating the from time when we had both the QEMU & generic remote protocol
there are tiny qemud/protocol.{x,c,h} files basically just containing
one struct for the packet header. This is more or less duplicated in the
remote protocol & with a few small tweaks can simplify this code. So the
attached patch removes the protocol.{x,c,h} files. The qemud.c file in
the 'receive header' branch now merely reads a single 4 byte unsigned
int to discover the packet length. The rest of the packet is dealt with
in the 'receive payload' branch. It immediately dispatches to the remote
program. There is no wire format change here - shouuld just be code cleanup
a/qemud/protocol.c | 17 --------------
a/qemud/protocol.h | 39 --------------------------------
a/qemud/protocol.x | 40 ---------------------------------
qemud/Makefile.am | 5 ----
qemud/internal.h | 1
qemud/qemud.c | 57 +++++++++++++++---------------------------------
qemud/remote.c | 2 -
qemud/remote_protocol.h | 1
qemud/remote_protocol.x | 3 ++
src/Makefile.am | 1
10 files changed, 24 insertions(+), 142 deletions(-)
Dan.
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules: http://search.cpan.org/~danberr/ -=|
|=- Projects: http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
17 years, 1 month
[Libvir] BuildRequires check
by Jim Meyering
Hi,
I tried to configure libvirt from cvs on a just-built rawhide system
and it failed like this, since I hadn't installed the "check" package,
which defines PKG_CHECK_EXISTS:
checking for init script flavor... redhat
checking for iptables... /sbin/iptables
./configure: line 12187: syntax error near unexpected token `libxml-2.0,LIBXML_FOUND=yes'
./configure: line 12187: ` PKG_CHECK_EXISTS(libxml-2.0,LIBXML_FOUND=yes)'
Here's a fix:
2007-10-17 Jim Meyering <meyering(a)redhat.com>
* libvirt.spec.in (BuildRequires): Add "check".
Index: libvirt.spec.in
===================================================================
RCS file: /data/cvs/libvirt/libvirt.spec.in,v
retrieving revision 1.65
diff -u -p -r1.65 libvirt.spec.in
--- libvirt.spec.in 12 Oct 2007 19:54:15 -0000 1.65
+++ libvirt.spec.in 17 Oct 2007 10:03:22 -0000
@@ -16,6 +16,7 @@ Requires: ncurses
Requires: dnsmasq
Requires: bridge-utils
Requires: iptables
+BuildRequires: check
BuildRequires: xen-devel
BuildRequires: libxml2-devel
BuildRequires: readline-devel
17 years, 1 month
[Libvir] "make check" requires qemu
by Jim Meyering
So perhaps libvirt should BuildRequire qemu, too?
When I ran "make check" on a system without qemu,
I got lots of failures:
...
QEMU XML-2-ARGV Misc ACPI ... FAILED
libvir: QEMU error : Cannot find QEMU binary /usr/bin/qemu: No such file or directory
QEMU XML-2-ARGV Misc No Reboot ... FAILED
libvir: QEMU error : Cannot find QEMU binary /usr/bin/qemu: No such file or directory
QEMU XML-2-ARGV Net User ... FAILED
FAIL: qemuxml2argvtest
Here's a patch:
2007-10-17 Jim Meyering <meyering(a)redhat.com>
* libvirt.spec.in (BuildRequires): Add "qemu".
Index: libvirt.spec.in
===================================================================
RCS file: /data/cvs/libvirt/libvirt.spec.in,v
retrieving revision 1.65
diff -u -p -r1.65 libvirt.spec.in
--- libvirt.spec.in 12 Oct 2007 19:54:15 -0000 1.65
+++ libvirt.spec.in 17 Oct 2007 10:11:33 -0000
@@ -25,6 +25,7 @@ BuildRequires: gnutls-devel
BuildRequires: avahi-devel
BuildRequires: dnsmasq
BuildRequires: bridge-utils
+BuildRequires: qemu
Obsoletes: libvir
ExclusiveArch: i386 x86_64 ia64
17 years, 1 month
[Libvir] sexpr_get: add __printf__ attribute
by Jim Meyering
I noticed sexpr_get takes a printf-style format,
yet it is declared with no printf attribute. Here's the fix:
2007-10-17 Jim Meyering <meyering(a)redhat.com>
* src/xend_internal.c (sexpr_get): Declare with gcc's printf attribute.
Index: src/xend_internal.c
===================================================================
RCS file: /data/cvs/libvirt/src/xend_internal.c,v
retrieving revision 1.148
diff -u -p -r1.148 xend_internal.c
--- src/xend_internal.c 15 Oct 2007 21:38:56 -0000 1.148
+++ src/xend_internal.c 17 Oct 2007 08:29:26 -0000
@@ -692,6 +692,10 @@ xend_op(virConnectPtr xend, const char *
*/
static struct sexpr *
sexpr_get(virConnectPtr xend, const char *fmt, ...)
+ __attribute__ ((__format__ (__printf__, 2, 3)));
+
+static struct sexpr *
+sexpr_get(virConnectPtr xend, const char *fmt, ...)
{
char buffer[4096];
char path[1024];
17 years, 1 month