1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
|
<?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">
<!--
This file is autogenerated from aclpolkit.html.in
Do not edit this file. Changes will be lost.
-->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="main.css" />
<link rel="SHORTCUT ICON" href="32favicon.png" />
<title>libvirt: Polkit access control</title>
<meta name="description" content="libvirt, virtualization, virtualization API" />
</head>
<body>
<div id="body">
<div id="content">
<h1>Polkit access control</h1>
<p>
Libvirt's client <a href="acl.html" shape="rect">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.
</p>
<ul><li>
<a href="#intro">Introduction</a>
</li><li>
<a href="#perms">Permission names</a>
</li><li>
<a href="#attrs">Object identity attributes</a>
<ul><li>
<a href="#object_connect">virConnectPtr</a>
</li><li>
<a href="#object_domain">virDomainPtr</a>
</li><li>
<a href="#object_interface">virInterfacePtr</a>
</li><li>
<a href="#object_network">virNetworkPtr</a>
</li><li>
<a href="#object_node_device">virNodeDevicePtr</a>
</li><li>
<a href="#object_nwfilter">virNWFilterPtr</a>
</li><li>
<a href="#object_secret">virSecretPtr</a>
</li><li>
<a href="#object_storage_pool">virStoragePoolPtr</a>
</li><li>
<a href="#object_storage_vol">virStorageVolPtr</a>
</li></ul>
</li><li>
<a href="#user">User identity attributes</a>
</li><li>
<a href="#checks">Writing access control policies</a>
<ul><li>
<a href="#exconnect">Example: restricting ability to connect to drivers</a>
</li><li>
<a href="#exdomain">Example: restricting access to a single domain</a>
</li></ul>
</li></ul>
<h2>
<a name="intro" shape="rect" id="intro">Introduction</a>
<a class="headerlink" href="#intro" title="Permalink to this headline">¶</a>
</h2>
<p>
A default install of libvirt will typically use
<a href="http://www.freedesktop.org/wiki/Software/polkit/" shape="rect">polkit</a>
to authenticate the initial user connection to libvirtd. This is a
very coarse grained check though, either allowing full read-write
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" shape="rect" id="perms">Permission names</a>
<a class="headerlink" href="#perms" title="Permalink to this headline">¶</a>
</h2>
<p>
The libvirt <a href="acl.html#perms" shape="rect">object names and permission names</a>
are mapped onto polkit action names using the simple pattern:
</p>
<pre xml:space="preserve">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 xml:space="preserve">org.libvirt.api.storage-pool.search-storage-vols
</pre>
<p>
The default policy for any permission which corresponds to
a "read only" operation, is to allow access. All other
permissions default to deny access.
</p>
<h2>
<a name="attrs" shape="rect" id="attrs">Object identity attributes</a>
<a class="headerlink" href="#attrs" title="Permalink to this headline">¶</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" shape="rect" id="object_connect">virConnectPtr</a>
<a class="headerlink" href="#object_connect" title="Permalink to this headline">¶</a>
</h3>
<table class="acl"><thead><tr><th rowspan="1" colspan="1">Attribute</th><th rowspan="1" colspan="1">Description</th></tr></thead><tbody><tr><td rowspan="1" colspan="1">connect_driver</td><td rowspan="1" colspan="1">Name of the libvirt connection driver</td></tr></tbody></table>
<h3>
<a name="object_domain" shape="rect" id="object_domain">virDomainPtr</a>
<a class="headerlink" href="#object_domain" title="Permalink to this headline">¶</a>
</h3>
<table class="acl"><thead><tr><th rowspan="1" colspan="1">Attribute</th><th rowspan="1" colspan="1">Description</th></tr></thead><tbody><tr><td rowspan="1" colspan="1">connect_driver</td><td rowspan="1" colspan="1">Name of the libvirt connection driver</td></tr><tr><td rowspan="1" colspan="1">domain_name</td><td rowspan="1" colspan="1">Name of the domain, unique to the local host</td></tr><tr><td rowspan="1" colspan="1">domain_uuid</td><td rowspan="1" colspan="1">UUID of the domain, globally unique</td></tr></tbody></table>
<h3>
<a name="object_interface" shape="rect" id="object_interface">virInterfacePtr</a>
<a class="headerlink" href="#object_interface" title="Permalink to this headline">¶</a>
</h3>
<table class="acl"><thead><tr><th rowspan="1" colspan="1">Attribute</th><th rowspan="1" colspan="1">Description</th></tr></thead><tbody><tr><td rowspan="1" colspan="1">connect_driver</td><td rowspan="1" colspan="1">Name of the libvirt connection driver</td></tr><tr><td rowspan="1" colspan="1">interface_name</td><td rowspan="1" colspan="1">Name of the network interface, unique to the local host</td></tr><tr><td rowspan="1" colspan="1">interface_macaddr</td><td rowspan="1" colspan="1">MAC address of the network interface, not unique</td></tr></tbody></table>
<h3>
<a name="object_network" shape="rect" id="object_network">virNetworkPtr</a>
<a class="headerlink" href="#object_network" title="Permalink to this headline">¶</a>
</h3>
<table class="acl"><thead><tr><th rowspan="1" colspan="1">Attribute</th><th rowspan="1" colspan="1">Description</th></tr></thead><tbody><tr><td rowspan="1" colspan="1">connect_driver</td><td rowspan="1" colspan="1">Name of the libvirt connection driver</td></tr><tr><td rowspan="1" colspan="1">network_name</td><td rowspan="1" colspan="1">Name of the network, unique to the local host</td></tr><tr><td rowspan="1" colspan="1">network_uuid</td><td rowspan="1" colspan="1">UUID of the network, globally unique</td></tr></tbody></table>
<h3>
<a name="object_node_device" shape="rect" id="object_node_device">virNodeDevicePtr</a>
<a class="headerlink" href="#object_node_device" title="Permalink to this headline">¶</a>
</h3>
<table class="acl"><thead><tr><th rowspan="1" colspan="1">Attribute</th><th rowspan="1" colspan="1">Description</th></tr></thead><tbody><tr><td rowspan="1" colspan="1">connect_driver</td><td rowspan="1" colspan="1">Name of the libvirt connection driver</td></tr><tr><td rowspan="1" colspan="1">node_device_name</td><td rowspan="1" colspan="1">Name of the node device, unique to the local host</td></tr></tbody></table>
<h3>
<a name="object_nwfilter" shape="rect" id="object_nwfilter">virNWFilterPtr</a>
<a class="headerlink" href="#object_nwfilter" title="Permalink to this headline">¶</a>
</h3>
<table class="acl"><thead><tr><th rowspan="1" colspan="1">Attribute</th><th rowspan="1" colspan="1">Description</th></tr></thead><tbody><tr><td rowspan="1" colspan="1">connect_driver</td><td rowspan="1" colspan="1">Name of the libvirt connection driver</td></tr><tr><td rowspan="1" colspan="1">nwfilter_name</td><td rowspan="1" colspan="1">Name of the network filter, unique to the local host</td></tr><tr><td rowspan="1" colspan="1">nwfilter_uuid</td><td rowspan="1" colspan="1">UUID of the network filter, globally unique</td></tr></tbody></table>
<h3>
<a name="object_secret" shape="rect" id="object_secret">virSecretPtr</a>
<a class="headerlink" href="#object_secret" title="Permalink to this headline">¶</a>
</h3>
<table class="acl"><thead><tr><th rowspan="1" colspan="1">Attribute</th><th rowspan="1" colspan="1">Description</th></tr></thead><tbody><tr><td rowspan="1" colspan="1">connect_driver</td><td rowspan="1" colspan="1">Name of the libvirt connection driver</td></tr><tr><td rowspan="1" colspan="1">secret_uuid</td><td rowspan="1" colspan="1">UUID of the secret, globally unique</td></tr><tr><td rowspan="1" colspan="1">secret_usage_volume</td><td rowspan="1" colspan="1">Name of the associated volume, if any</td></tr><tr><td rowspan="1" colspan="1">secret_usage_ceph</td><td rowspan="1" colspan="1">Name of the associated Ceph server, if any</td></tr><tr><td rowspan="1" colspan="1">secret_usage_target</td><td rowspan="1" colspan="1">Name of the associated iSCSI target, if any</td></tr><tr><td rowspan="1" colspan="1">secret_usage_name</td><td rowspan="1" colspan="1">Name of the associated TLS secret, if any</td></tr></tbody></table>
<h3>
<a name="object_storage_pool" shape="rect" id="object_storage_pool">virStoragePoolPtr</a>
<a class="headerlink" href="#object_storage_pool" title="Permalink to this headline">¶</a>
</h3>
<table class="acl"><thead><tr><th rowspan="1" colspan="1">Attribute</th><th rowspan="1" colspan="1">Description</th></tr></thead><tbody><tr><td rowspan="1" colspan="1">connect_driver</td><td rowspan="1" colspan="1">Name of the libvirt connection driver</td></tr><tr><td rowspan="1" colspan="1">pool_name</td><td rowspan="1" colspan="1">Name of the storage pool, unique to the local host</td></tr><tr><td rowspan="1" colspan="1">pool_uuid</td><td rowspan="1" colspan="1">UUID of the storage pool, globally unique</td></tr></tbody></table>
<h3>
<a name="object_storage_vol" shape="rect" id="object_storage_vol">virStorageVolPtr</a>
<a class="headerlink" href="#object_storage_vol" title="Permalink to this headline">¶</a>
</h3>
<table class="acl"><thead><tr><th rowspan="1" colspan="1">Attribute</th><th rowspan="1" colspan="1">Description</th></tr></thead><tbody><tr><td rowspan="1" colspan="1">connect_driver</td><td rowspan="1" colspan="1">Name of the libvirt connection driver</td></tr><tr><td rowspan="1" colspan="1">pool_name</td><td rowspan="1" colspan="1">Name of the storage pool, unique to the local host</td></tr><tr><td rowspan="1" colspan="1">pool_uuid</td><td rowspan="1" colspan="1">UUID of the storage pool, globally unique</td></tr><tr><td rowspan="1" colspan="1">vol_name</td><td rowspan="1" colspan="1">Name of the storage volume, unique to the pool</td></tr><tr><td rowspan="1" colspan="1">vol_key</td><td rowspan="1" colspan="1">Key of the storage volume, globally unique</td></tr></tbody></table>
<h2>
<a name="user" shape="rect" id="user">User identity attributes</a>
<a class="headerlink" href="#user" title="Permalink to this headline">¶</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 and access will be denied.
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
SASL / Kerberos username and/or x509 distinguished
name obtained from the authentication provider in use.
</p>
<h2>
<a name="checks" shape="rect" id="checks">Writing access control policies</a>
<a class="headerlink" href="#checks" title="Permalink to this headline">¶</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. The latter is what will be
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 xml:space="preserve">
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 the
<code>lookup</code> method.
</p>
<p>
See
<a href="http://libvirt.org/git/?p=libvirt.git;a=tree;f=examples/polkit;hb=HEAD" shape="rect">source code</a>
for a more complex example.
</p>
<h3>
<a name="exconnect" shape="rect" id="exconnect">Example: restricting ability to connect to drivers</a>
<a class="headerlink" href="#exconnect" title="Permalink to this headline">¶</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>connect_driver</code> attribute
is <code>QEMU</code>, and match on an action
name of <code>org.libvirt.api.connect.getattr</code>. Using
the javascript rules format, this ends up written as
</p>
<pre xml:space="preserve">
polkit.addRule(function(action, subject) {
if (action.id == "org.libvirt.api.connect.getattr" &&
subject.user == "berrange") {
if (action.lookup("connect_driver") == 'QEMU') {
return polkit.Result.YES;
} else {
return polkit.Result.NO;
}
}
});
</pre>
<h3>
<a name="exdomain" shape="rect" id="exdomain">Example: restricting access to a single domain</a>
<a class="headerlink" href="#exdomain" title="Permalink to this headline">¶</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>connect_driver</code> attribute
is <code>LXC</code> and the <code>domain_name</code>
attribute is <code>demo</code>, and match on a action
name of <code>org.libvirt.api.domain.getattr</code>. Using
the javascript rules format, this ends up written as
</p>
<pre xml:space="preserve">
polkit.addRule(function(action, subject) {
if (action.id == "org.libvirt.api.domain.getattr" &&
subject.user == "berrange") {
if (action.lookup("connect_driver") == 'LXC' &&
action.lookup("domain_name") == 'demo') {
return polkit.Result.YES;
} else {
return polkit.Result.NO;
}
}
});
</pre>
</div>
</div>
<div id="nav">
<div id="home">
<a href="index.html">Home</a>
</div>
<div id="jumplinks">
<ul><li>
<a href="downloads.html">Download</a>
</li><li>
<a href="contribute.html">Contribute</a>
</li><li>
<a href="docs.html">Learn</a>
</li></ul>
</div>
<div id="search">
<form action="search.php" enctype="application/x-www-form-urlencoded" method="get"><div>
<input name="query" type="text" size="12" value="" />
<input name="submit" type="submit" value="Go" />
</div></form>
</div>
</div>
<div id="footer">
<div id="contact">
<h3>Contact</h3>
<ul><li>
<a href="contact.html#email">email</a>
</li><li>
<a href="contact.html#irc">irc</a>
</li></ul>
</div>
<div id="community">
<h3>Community</h3>
<ul><li>
<a href="https://twitter.com/hashtag/libvirt">twitter</a>
</li><li>
<a href="https://plus.google.com/communities/109522598353007505282">google+</a>
</li><li>
<a href="http://stackoverflow.com/questions/tagged/libvirt">stackoverflow</a>
</li><li>
<a href="http://serverfault.com/questions/tagged/libvirt">serverfault</a>
</li></ul>
</div>
<div id="conduct">
Participants in the libvirt project agree to abide by <a href="governance.html#codeofconduct">the project code of conduct</a></div>
<br class="clear" />
</div>
</body>
</html>
|