On 08/08/2013 05:27 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange(a)redhat.com>
This adds two new pages to the website, acl.html describing
the general access control framework and permissions models,
and aclpolkit.html describing the use of polkit as an
access control driver.
page.xsl is modified to support a new syntax
<div id="include" filename="somefile.htmlinc"/>
which will cause the XSL transform to replace that <div>
with the contents of 'somefile.htmlinc'. We use this in
the acl.html.in file, to pull the table of permissions
for each libvirt object. This table is autogenerated
from the enums in src/access/viraccessperms.h by the
genaclperms.pl script.
newapi.xsl is modified so that the list of permissions
checks shown against each API will link to the description
of the permissions in acl.html
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
.gitignore | 1 +
docs/Makefile.am | 12 +-
docs/acl.html.in | 100 ++++++++++++
docs/aclpolkit.html.in | 414 +++++++++++++++++++++++++++++++++++++++++++++++++
docs/auth.html.in | 6 +-
docs/genaclperms.pl | 124 +++++++++++++++
docs/newapi.xsl | 4 +-
docs/page.xsl | 11 ++
docs/sitemap.html.in | 10 ++
9 files changed, 677 insertions(+), 5 deletions(-)
create mode 100644 docs/acl.html.in
create mode 100644 docs/aclpolkit.html.in
create mode 100644 docs/genaclperms.pl
[I still need to look into why, in a clean checkout, 'make distcheck'
fails when 'make all distcheck' passes, but that shoudln't hold up this
patch, whether or not this patch aggravates the issue]
+aclperms.htmlinc: $(top_srcdir)/src/access/viraccessperm.h \
+ genaclperms.pl Makefile.am
+ $(PERL) genaclperms.pl $< > $@
Did you test a VPATH build?
+ <p>
+ In a default configuration, the libvirtd daemon have three levels
s/have/has/
+ of access control. All connections start off in an
unauthenticated
+ state, where the only API operations allowed are those required
+ to complete authentication. After successful authentication, a
+ connection either has full, unrestricted access to all libvirt
+ API calls, or is locked down to only "read only" operations,
+ according to what socket a client connection originated on.
+ </p>
+
+ <p>
+ The access control framework allows authenticated connections to
+ have fine grained permission rules to be defined by the administrator.
+ Every API call in libvirt has a set of permissions that will
+ be validated against the object being used. For example, the
+ <code>virDomainSetSchedulerParametersFlags</code> method will
+ check whether the client user has the <code>write</code>
+ permission on the <code>domain</code> object instance passed
+ in as a parameter. Further permissions will also be checked
+ if certain flags are set in the API call. In addition to
+ checks on the object passed into an API call, some methods
s/into/in to/
+ will filter their results. For example the
<code>virConnectListAllDomains</code>
+ method will check the <code>search_domains</code> on the
<code>connect</code>
+ object, but will also filter the returned <code>domain</code>
+ objects to only those on which the client user has the
+ <code>getattr</code> permission.
+ </p>
+
+ <h2><a name="drivers">Access control
drivers</a></h2>
+
+ <p>
+ The access control framework is designed as a pluggable
+ system to enable future integration with arbitrary access
+ control technologies. By default, the <code>none</code>
+ driver is used, which does not access controll checks at
s/not/no/; s/controll/control/
+ all. At this time, libvirt ships with support for using
+ <a
href="http://www.freedesktop.org/wiki/Software/polkit/">polk... as a
real access
+ control driver. To learn how to use the polkit access
+ driver consult <a href="aclpolkit.html">the configuration
+ docs</a>.
+ </p>
+
+ <p>
+ The access driver is configured in the <code>libvirtd.conf</code>
+ configuration file, using the <code>access_drivers</code>
+ parameter. This parameter accepts an array of access control
+ driver names. If more than one access driver is requested,
+ then all must succeed in order for access to be granted.
+ To enable 'polkit' as the driver
+ </p>
+
+ <pre>
+# augtool -s set '/files/etc/libvirt/libvirtd.conf/access_drivers[1]' polkit
+ </pre>
+
+ <p>
+ And to reset back to the default (no-op) driver
+ </p>
+
+
+ <pre>
+# augtool -s rm /files/etc/libvirt/libvirtd.conf/access_drivers
+ </pre>
+
+ <p>
+ <strong>Note:</strong> changes to libvirtd.conf require that
+ the libvirtd daemon be restarted.
Isn't sending SIGHUP sufficient, or does it have to be a full restart?
+ </p>
+
+ <h2><a name="perms">Objects and
permissions</a></h2>
+
+ <p>
+ Libvirt applies access control to all the main object
+ types in its API. Each object type, in turn, has a set
+ of permissions defined. To determine what permissions
+ are checked for specific API call, consult the
+ <a href="html/libvirt-libvirt.html">API reference
manual</a>
+ documentation for the API in question.
+ </p>
+
+ <div id="include" filename="aclperms.htmlinc"/>
+
+ </body>
+</html>
diff --git a/docs/aclpolkit.html.in b/docs/aclpolkit.html.in
new file mode 100644
index 0000000..d7be0bd
--- /dev/null
+++ b/docs/aclpolkit.html.in
@@ -0,0 +1,414 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html
xmlns="http://www.w3.org/1999/xhtml">
+ <body>
+ <h1>Polkit access control</h1>
+
+ <p>
+ Libvirt's client <a href="acl.html">access control
framework</a> allows
+ administrators to setup fine grained permission rules across client users,
+ managed objects and API operations. This allows client connections
+ to be locked down to a minimal set of privileges. The polkit driver
+ provides a simple implementation of the access control framework
s/$/./
+ </p>
+
+ <ul id="toc"></ul>
+
+ <h2><a name="intro">Introduction</a></h2>
+
+ <p>
+ A default install of libvirt will typically use
+ <a
href="http://www.freedesktop.org/wiki/Software/polkit/">polk...
+ to authenticate the initial user connection to libvirtd. This is a
+ very coarse grained check though either allowing full read-write
s/though/though,/
+ access to all APIs, or just read-only access. The polkit
access
+ control driver in libvirt builds on this capability to allow for
+ fine grained control over the operations a user may perform on an
+ object.
+ </p>
+
+ <h2><a name="perms">Permission names</a></h2>
+
+ <p>
+ The libvirt <a href="acl.html#perms">object names and permission
names</a>
+ are mapped onto polkit action names using the simple pattern:
+ </p>
+
+ <pre>org.libvirt.api.$object.$permission
+</pre>
+
+ <p>
+ The only caveat is that any underscore characters in the
+ object or permission names are converted to hyphens. So,
+ for example, the <code>search_storage_vols</code> permission
+ on the <code>storage_pool</code> object maps to the polkit
+ action:
+ </p>
+ <pre>org.libvirt.api.storage-pool.search-storage-vols
+</pre>
+
+ <p>
+ The default policy for any permission which corresponds to
+ an "read only" operation, is to allow access. All other
s/an/a/
+ permissions default to deny access.
+ </p>
+
+ <h2><a name="attrs">Object identity
attributes</a></h2>
+
+ <p>
+ To allow polkit authorization rules to be written to match
+ against individual object instances, libvirt provides a number
+ of authorization detail attributes when performing a permission
+ check. The set of attributes varies according to the type
+ of object being checked
+ </p>
+
+ <h3><a
name="object_connect">virConnectPtr</a></h3>
+ <table class="acl">
+
+ <h3><a name="object_secret">virSecretPtr</a></h3>
+ <table class="acl">
+ <tr>
+ <td></td>
+ <td></td>
+ </tr>
Drop the empty row.
+
+ <h2><a name="user">User identity
attributes</a></h2>
+
+ <p>
+ At this point in time, the only attribute provided by
+ libvirt to identify the user invoking the operation
+ is the PID of the client program. This means that the
+ polkit access control driver is only useful if connections
+ to libvirt are restricted to its UNIX domain socket. If
+ connections are being made to a TCP socket, no identifying
+ information is available & access will be denied.
s/&/and/
+ Also note that if the client is connecting via an SSH
+ tunnel, it is the local SSH user that will be identified.
+ In future versions, it is expected that more information
+ about the client user will be provided, including the
+ SASAL / Kerberos username and/or x509 distinguished
s/SASAL/SASL/
+ name obtained from the authentication provider in use.
+ </p>
+
+
+ <h2><a name="checks">Writing acces control
policies</a></h2>
+
+ <p>
+ If using versions of polkit prior to 0.106 then it is only
+ possible to validate (user, permission) pairs via the
<code>.pkla</code>
+ files. Fully validation of the (user, permission, object) triple
+ requires the new JavaScript <code>.rules</code> support that
+ was introduced in version 0.106. That latter is what will be
s/That/The/
+ described here.
+ </p>
+
+ <p>
+ Libvirt does not ship any rules files by default. It merely
+ provides a definition of the default behaviour for each
+ action (permission). As noted earlier, permissions which
+ correspond to read-only operations in libvirt will be allowed
+ to all users by default; everything else is denied by default.
+ Defining custom rules requires creation of a file in the
+ <code>/etc/polkit-1/rules.d</code> directory with a name
+ chosen by the administrator (<code>100-libvirt-acl.rules</code>
+ would be a reasonable choice). See the <code>polkit(8)</code>
+ manual page for a description of how to write these files
+ in general. The key idea is to create a file containing
+ something like
+ </p>
+
+ <pre>
+ polkit.addRule(function(action, subject) {
+ ....logic to check 'action' and 'subject'...
+ });
+ </pre>
+
+ <p>
+ In this code snippet above, the <code>action</code> object
+ instance will represent the libvirt permission being checked
+ along with identifying attributes for the object it is being
+ applied to. The <code>subject</code> meanwhile will identify
+ the libvirt client app (with the caveat above about it only
+ dealing with local clients connected via the UNIX socket).
+ On the <code>action</code> object, the permission name is
+ accessible via the <code>id</code> attribute, while the
+ object identifying attributes are exposed via a set of
+ attributes with the naming convention
<code>_detail_[attrname]</code>.
+ For example, the 'domain_name' attribute would be exposed via
+ a property <code>_detail_domain_name</code>.
+ </p>
+
+ <h3><a name="exconnect">Example: restricting ability to
connect to drivers</a></h3>
+
+ <p>
+ Consider a local user <code>berrange</code>
+ who has been granted permission to connect to libvirt in
+ full read-write mode. The goal is to only allow them to
+ use the <code>QEMU</code> driver and not the Xen or LXC
+ drivers which are also available in libvirtd.
+ To achieve this we need to write a rule which checks
+ whether the <code>_detail_connect_driver</code> attribute
+ is <code>QEMU</code>, and match on a action
+ name of <code>org.libvirt.api.connect.getattr</code>. Using
+ the javascript rules format, this ends up written as
+ </p>
+
+ <pre>
+polkit.addRule(function(action, subject) {
+ if (action.id == "org.libvirt.api.connect.getattr" &&
+ subject.user == "berrange") {
+ if (action._detail_connect_driver == 'QEMU') {
+ return polkit.Result.YES;
+ } else {
+ return polkit.Result.NO;
+ }
+ }
This function has no return statement when the initial 'if' is not
satisfied; is that valid?
+});
+ </pre>
+
+ <h3><a name="exdomain">Example: restricting access to a single
domain</a></h3>
+
+ <p>
+ Consider a local user <code>berrange</code>
+ who has been granted permission to connect to libvirt in
+ full read-write mode. The goal is to only allow them to
+ see the domain called <code>demo</code> on the LXC driver.
+ To achieve this we need to write a rule which checks
+ whether the <code>_detail_connect_driver</code> attribute
+ is <code>LXC</code> and the
<code>_detail_domain_name</code>
+ attribute is <code>demo</code>, and match on a action
s/a /an /
+ name of
<code>org.libvirt.api.domain.getattr</code>. Using
+ the javascript rules format, this ends up written as
+ </p>
+
+ <pre>
+polkit.addRule(function(action, subject) {
+ if (action.id == "org.libvirt.api.domain.getattr" &&
+ subject.user == "berrange") {
+ if (action._detail_connect_driver == 'LXC' &&
+ action._detail_domain_name == 'busy') {
+ return polkit.Result.YES;
+ } else {
+ return polkit.Result.NO;
+ }
+ }
Again, what happens when you fall off the end of a rule without a return?
+});
+ </pre>
+ </body>
+</html>
diff --git a/docs/auth.html.in b/docs/auth.html.in
index e5703c7..37f2978 100644
--- a/docs/auth.html.in
+++ b/docs/auth.html.in
@@ -2,12 +2,14 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html
xmlns="http://www.w3.org/1999/xhtml">
<body>
- <h1 >Authentication & access control</h1>
+ <h1>Connection authentication</h1>
<p>
When connecting to libvirt, some connections may require client
authentication before allowing use of the APIs. The set of possible
authentication mechanisms is administrator controlled, independent
- of applications using libvirt.
+ of applications using libvirt. Once authenticated, libvirt can apply
+ fine grained <a href="acl.html">access control</a> to the
operations
+ performed by a client.
</p>
<ul id="toc"></ul>
diff --git a/docs/genaclperms.pl b/docs/genaclperms.pl
new file mode 100644
index 0000000..244a68e
--- /dev/null
+++ b/docs/genaclperms.pl
'chmod +x' before pushing, to match the permissions of all our other .pl
files.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library
http://libvirt.org