tests: Use the new DO_TEST_CAPS_*() macros
[libvirt/ericb.git] / docs / aclpolkit.html.in
blob2cf1f9b5a59c0a1a604d9e7b5409938268759430
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE html>
3 <html xmlns="http://www.w3.org/1999/xhtml">
4 <body>
5 <h1>Polkit access control</h1>
7 <p>
8 Libvirt's client <a href="acl.html">access control framework</a> allows
9 administrators to setup fine grained permission rules across client users,
10 managed objects and API operations. This allows client connections
11 to be locked down to a minimal set of privileges. The polkit driver
12 provides a simple implementation of the access control framework.
13 </p>
15 <ul id="toc"></ul>
17 <h2><a id="intro">Introduction</a></h2>
19 <p>
20 A default install of libvirt will typically use
21 <a href="http://www.freedesktop.org/wiki/Software/polkit/">polkit</a>
22 to authenticate the initial user connection to libvirtd. This is a
23 very coarse grained check though, either allowing full read-write
24 access to all APIs, or just read-only access. The polkit access
25 control driver in libvirt builds on this capability to allow for
26 fine grained control over the operations a user may perform on an
27 object.
28 </p>
30 <h2><a id="perms">Permission names</a></h2>
32 <p>
33 The libvirt <a href="acl.html#perms">object names and permission names</a>
34 are mapped onto polkit action names using the simple pattern:
35 </p>
37 <pre>org.libvirt.api.$object.$permission
38 </pre>
40 <p>
41 The only caveat is that any underscore characters in the
42 object or permission names are converted to hyphens. So,
43 for example, the <code>search_storage_vols</code> permission
44 on the <code>storage_pool</code> object maps to the polkit
45 action:
46 </p>
47 <pre>org.libvirt.api.storage-pool.search-storage-vols
48 </pre>
50 <p>
51 The default policy for any permission which corresponds to
52 a "read only" operation, is to allow access. All other
53 permissions default to deny access.
54 </p>
56 <h2><a id="attrs">Object identity attributes</a></h2>
58 <p>
59 To allow polkit authorization rules to be written to match
60 against individual object instances, libvirt provides a number
61 of authorization detail attributes when performing a permission
62 check. The set of attributes varies according to the type
63 of object being checked
64 </p>
66 <h3><a id="object_connect">virConnectPtr</a></h3>
67 <table class="acl">
68 <thead>
69 <tr>
70 <th>Attribute</th>
71 <th>Description</th>
72 </tr>
73 </thead>
74 <tbody>
75 <tr>
76 <td>connect_driver</td>
77 <td>Name of the libvirt connection driver</td>
78 </tr>
79 </tbody>
80 </table>
82 <h3><a id="object_domain">virDomainPtr</a></h3>
83 <table class="acl">
84 <thead>
85 <tr>
86 <th>Attribute</th>
87 <th>Description</th>
88 </tr>
89 </thead>
90 <tbody>
91 <tr>
92 <td>connect_driver</td>
93 <td>Name of the libvirt connection driver</td>
94 </tr>
95 <tr>
96 <td>domain_name</td>
97 <td>Name of the domain, unique to the local host</td>
98 </tr>
99 <tr>
100 <td>domain_uuid</td>
101 <td>UUID of the domain, globally unique</td>
102 </tr>
103 </tbody>
104 </table>
106 <h3><a id="object_interface">virInterfacePtr</a></h3>
107 <table class="acl">
108 <thead>
109 <tr>
110 <th>Attribute</th>
111 <th>Description</th>
112 </tr>
113 </thead>
114 <tbody>
115 <tr>
116 <td>connect_driver</td>
117 <td>Name of the libvirt connection driver</td>
118 </tr>
119 <tr>
120 <td>interface_name</td>
121 <td>Name of the network interface, unique to the local host</td>
122 </tr>
123 <tr>
124 <td>interface_macaddr</td>
125 <td>MAC address of the network interface, not unique</td>
126 </tr>
127 </tbody>
128 </table>
130 <h3><a id="object_network">virNetworkPtr</a></h3>
131 <table class="acl">
132 <thead>
133 <tr>
134 <th>Attribute</th>
135 <th>Description</th>
136 </tr>
137 </thead>
138 <tbody>
139 <tr>
140 <td>connect_driver</td>
141 <td>Name of the libvirt connection driver</td>
142 </tr>
143 <tr>
144 <td>network_name</td>
145 <td>Name of the network, unique to the local host</td>
146 </tr>
147 <tr>
148 <td>network_uuid</td>
149 <td>UUID of the network, globally unique</td>
150 </tr>
151 </tbody>
152 </table>
154 <h3><a id="object_node_device">virNodeDevicePtr</a></h3>
155 <table class="acl">
156 <thead>
157 <tr>
158 <th>Attribute</th>
159 <th>Description</th>
160 </tr>
161 </thead>
162 <tbody>
163 <tr>
164 <td>connect_driver</td>
165 <td>Name of the libvirt connection driver</td>
166 </tr>
167 <tr>
168 <td>node_device_name</td>
169 <td>Name of the node device, unique to the local host</td>
170 </tr>
171 </tbody>
172 </table>
174 <h3><a id="object_nwfilter">virNWFilterPtr</a></h3>
175 <table class="acl">
176 <thead>
177 <tr>
178 <th>Attribute</th>
179 <th>Description</th>
180 </tr>
181 </thead>
182 <tbody>
183 <tr>
184 <td>connect_driver</td>
185 <td>Name of the libvirt connection driver</td>
186 </tr>
187 <tr>
188 <td>nwfilter_name</td>
189 <td>Name of the network filter, unique to the local host</td>
190 </tr>
191 <tr>
192 <td>nwfilter_uuid</td>
193 <td>UUID of the network filter, globally unique</td>
194 </tr>
195 </tbody>
196 </table>
198 <h3><a id="object_secret">virSecretPtr</a></h3>
199 <table class="acl">
200 <thead>
201 <tr>
202 <th>Attribute</th>
203 <th>Description</th>
204 </tr>
205 </thead>
206 <tbody>
207 <tr>
208 <td>connect_driver</td>
209 <td>Name of the libvirt connection driver</td>
210 </tr>
211 <tr>
212 <td>secret_uuid</td>
213 <td>UUID of the secret, globally unique</td>
214 </tr>
215 <tr>
216 <td>secret_usage_volume</td>
217 <td>Name of the associated volume, if any</td>
218 </tr>
219 <tr>
220 <td>secret_usage_ceph</td>
221 <td>Name of the associated Ceph server, if any</td>
222 </tr>
223 <tr>
224 <td>secret_usage_target</td>
225 <td>Name of the associated iSCSI target, if any</td>
226 </tr>
227 <tr>
228 <td>secret_usage_name</td>
229 <td>Name of the associated TLS secret, if any</td>
230 </tr>
231 </tbody>
232 </table>
234 <h3><a id="object_storage_pool">virStoragePoolPtr</a></h3>
235 <table class="acl">
236 <thead>
237 <tr>
238 <th>Attribute</th>
239 <th>Description</th>
240 </tr>
241 </thead>
242 <tbody>
243 <tr>
244 <td>connect_driver</td>
245 <td>Name of the libvirt connection driver</td>
246 </tr>
247 <tr>
248 <td>pool_name</td>
249 <td>Name of the storage pool, unique to the local host</td>
250 </tr>
251 <tr>
252 <td>pool_uuid</td>
253 <td>UUID of the storage pool, globally unique</td>
254 </tr>
255 </tbody>
256 </table>
258 <h3><a id="object_storage_vol">virStorageVolPtr</a></h3>
259 <table class="acl">
260 <thead>
261 <tr>
262 <th>Attribute</th>
263 <th>Description</th>
264 </tr>
265 </thead>
266 <tbody>
267 <tr>
268 <td>connect_driver</td>
269 <td>Name of the libvirt connection driver</td>
270 </tr>
271 <tr>
272 <td>pool_name</td>
273 <td>Name of the storage pool, unique to the local host</td>
274 </tr>
275 <tr>
276 <td>pool_uuid</td>
277 <td>UUID of the storage pool, globally unique</td>
278 </tr>
279 <tr>
280 <td>vol_name</td>
281 <td>Name of the storage volume, unique to the pool</td>
282 </tr>
283 <tr>
284 <td>vol_key</td>
285 <td>Key of the storage volume, globally unique</td>
286 </tr>
287 </tbody>
288 </table>
290 <h2><a id="connect_driver">Hypervisor Driver connect_driver</a></h2>
292 The <code>connect_driver</code> parameter describes the
293 client's <a href="remote.html">remote Connection Driver</a>
294 name based on the <a href="uri.html">URI</a> used for the
295 connection.
296 </p>
298 <span class="since">Since 4.1.0</span>, when calling an API
299 outside the scope of the primary connection driver, the
300 primary driver will attempt to open a secondary connection
301 to the specific API driver in order to process the API. For
302 example, when hypervisor domain processing needs to make an
303 API call within the storage driver or the network filter driver
304 an attempt to open a connection to the "storage" or "nwfilter"
305 driver will be made. Similarly, a "storage" primary connection
306 may need to create a connection to the "secret" driver in order
307 to process secrets for the API. If successful, then calls to
308 those API's will occur in the <code>connect_driver</code> context
309 of the secondary connection driver rather than in the context of
310 the primary driver. This affects the <code>connect_driver</code>
311 returned from rule generation from the <code>action.loookup</code>
312 function. The following table provides a list of the various
313 connection drivers and the <code>connect_driver</code> name
314 used by each regardless of primary or secondary connection.
315 The access denied error message from libvirt will list the
316 connection driver by name that denied the access.
317 </p>
319 <h3><a id="object_connect_driver">Connection Driver Name</a></h3>
320 <table class="acl">
321 <thead>
322 <tr>
323 <th>Connection Driver</th>
324 <th><code>connect_driver</code> name</th>
325 </tr>
326 </thead>
327 <tbody>
328 <tr>
329 <td>bhyve</td>
330 <td>bhyve</td>
331 </tr>
332 <tr>
333 <td>esx</td>
334 <td>ESX</td>
335 </tr>
336 <tr>
337 <td>hyperv</td>
338 <td>Hyper-V</td>
339 </tr>
340 <tr>
341 <td>interface</td>
342 <td>interface</td>
343 </tr>
344 <tr>
345 <td>libxl</td>
346 <td>xenlight</td>
347 </tr>
348 <tr>
349 <td>lxc</td>
350 <td>LXC</td>
351 </tr>
352 <tr>
353 <td>network</td>
354 <td>network</td>
355 </tr>
356 <tr>
357 <td>nodedev</td>
358 <td>nodedev</td>
359 </tr>
360 <tr>
361 <td>nwfilter</td>
362 <td>NWFilter</td>
363 </tr>
364 <tr>
365 <td>openvz</td>
366 <td>OPENVZ</td>
367 </tr>
368 <tr>
369 <td>phyp</td>
370 <td>PHYP</td>
371 </tr>
372 <tr>
373 <td>qemu</td>
374 <td>QEMU</td>
375 </tr>
376 <tr>
377 <td>secret</td>
378 <td>secret</td>
379 </tr>
380 <tr>
381 <td>storage</td>
382 <td>storage</td>
383 </tr>
384 <tr>
385 <td>vbox</td>
386 <td>VBOX</td>
387 </tr>
388 <tr>
389 <td>vmware</td>
390 <td>VMWARE</td>
391 </tr>
392 <tr>
393 <td>vz</td>
394 <td>vz</td>
395 </tr>
396 <tr>
397 <td>xenapi</td>
398 <td>XenAPI</td>
399 </tr>
400 </tbody>
401 </table>
404 <h2><a id="user">User identity attributes</a></h2>
407 At this point in time, the only attribute provided by
408 libvirt to identify the user invoking the operation
409 is the PID of the client program. This means that the
410 polkit access control driver is only useful if connections
411 to libvirt are restricted to its UNIX domain socket. If
412 connections are being made to a TCP socket, no identifying
413 information is available and access will be denied.
414 Also note that if the client is connecting via an SSH
415 tunnel, it is the local SSH user that will be identified.
416 In future versions, it is expected that more information
417 about the client user will be provided, including the
418 SASL / Kerberos username and/or x509 distinguished
419 name obtained from the authentication provider in use.
420 </p>
423 <h2><a id="checks">Writing access control policies</a></h2>
426 If using versions of polkit prior to 0.106 then it is only
427 possible to validate (user, permission) pairs via the <code>.pkla</code>
428 files. Fully validation of the (user, permission, object) triple
429 requires the new JavaScript <code>.rules</code> support that
430 was introduced in version 0.106. The latter is what will be
431 described here.
432 </p>
435 Libvirt does not ship any rules files by default. It merely
436 provides a definition of the default behaviour for each
437 action (permission). As noted earlier, permissions which
438 correspond to read-only operations in libvirt will be allowed
439 to all users by default; everything else is denied by default.
440 Defining custom rules requires creation of a file in the
441 <code>/etc/polkit-1/rules.d</code> directory with a name
442 chosen by the administrator (<code>100-libvirt-acl.rules</code>
443 would be a reasonable choice). See the <code>polkit(8)</code>
444 manual page for a description of how to write these files
445 in general. The key idea is to create a file containing
446 something like
447 </p>
449 <pre>
450 polkit.addRule(function(action, subject) {
451 ....logic to check 'action' and 'subject'...
453 </pre>
456 In this code snippet above, the <code>action</code> object
457 instance will represent the libvirt permission being checked
458 along with identifying attributes for the object it is being
459 applied to. The <code>subject</code> meanwhile will identify
460 the libvirt client app (with the caveat above about it only
461 dealing with local clients connected via the UNIX socket).
462 On the <code>action</code> object, the permission name is
463 accessible via the <code>id</code> attribute, while the
464 object identifying attributes are exposed via the
465 <code>lookup</code> method.
466 </p>
470 <a href="https://libvirt.org/git/?p=libvirt.git;a=tree;f=examples/polkit;hb=HEAD">source code</a>
471 for a more complex example.
472 </p>
474 <h3><a id="exconnect">Example: restricting ability to connect to drivers</a></h3>
477 Consider a local user <code>berrange</code>
478 who has been granted permission to connect to libvirt in
479 full read-write mode. The goal is to only allow them to
480 use the <code>QEMU</code> driver and not the Xen or LXC
481 drivers which are also available in libvirtd.
482 To achieve this we need to write a rule which checks
483 whether the <code>connect_driver</code> attribute
484 is <code>QEMU</code>, and match on an action
485 name of <code>org.libvirt.api.connect.getattr</code>. Using
486 the javascript rules format, this ends up written as
487 </p>
489 <pre>
490 polkit.addRule(function(action, subject) {
491 if (action.id == "org.libvirt.api.connect.getattr" &amp;&amp;
492 subject.user == "berrange") {
493 if (action.lookup("connect_driver") == 'QEMU') {
494 return polkit.Result.YES;
495 } else {
496 return polkit.Result.NO;
500 </pre>
502 <h3><a id="exdomain">Example: restricting access to a single domain</a></h3>
505 Consider a local user <code>berrange</code>
506 who has been granted permission to connect to libvirt in
507 full read-write mode. The goal is to only allow them to
508 see the domain called <code>demo</code> on the LXC driver.
509 To achieve this we need to write a rule which checks
510 whether the <code>connect_driver</code> attribute
511 is <code>LXC</code> and the <code>domain_name</code>
512 attribute is <code>demo</code>, and match on an action
513 name of <code>org.libvirt.api.domain.getattr</code>. Using
514 the javascript rules format, this ends up written as
515 </p>
517 <pre>
518 polkit.addRule(function(action, subject) {
519 if (action.id == "org.libvirt.api.domain.getattr" &amp;&amp;
520 subject.user == "berrange") {
521 if (action.lookup("connect_driver") == 'LXC' &amp;&amp;
522 action.lookup("domain_name") == 'demo') {
523 return polkit.Result.YES;
524 } else {
525 return polkit.Result.NO;
529 </pre>
530 </body>
531 </html>