[libvirt] [PATCH v2] examples: Add example polkit ACL rules

Creating ACL rules is not exactly easy and existing examples are pretty simple. This patch adds a somewhat complex example which defines several roles. Admins can do everything, operators can do basic operations on any domain and several groups of users who act as operators but only on a limited set of domains. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Makefile.am | 2 +- configure.ac | 1 + examples/polkit/Makefile.am | 17 ++++++ examples/polkit/libvirt-acl.rules | 115 ++++++++++++++++++++++++++++++++++++++ libvirt.spec.in | 3 + 5 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 examples/polkit/Makefile.am create mode 100644 examples/polkit/libvirt-acl.rules diff --git a/Makefile.am b/Makefile.am index 91b943b..d338d5a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,7 +23,7 @@ SUBDIRS = . gnulib/lib include src daemon tools docs gnulib/tests \ tests po examples/object-events examples/hellolibvirt \ examples/dominfo examples/domsuspend examples/apparmor \ examples/xml/nwfilter examples/openauth examples/systemtap \ - tools/wireshark examples/dommigrate \ + tools/wireshark examples/dommigrate examples/polkit \ examples/lxcconvert examples/domtop ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index 8471a46..136c2e7 100644 --- a/configure.ac +++ b/configure.ac @@ -2809,6 +2809,7 @@ AC_CONFIG_FILES([\ examples/systemtap/Makefile \ examples/xml/nwfilter/Makefile \ examples/lxcconvert/Makefile \ + examples/polkit/Makefile \ tools/wireshark/Makefile \ tools/wireshark/src/Makefile]) AC_OUTPUT diff --git a/examples/polkit/Makefile.am b/examples/polkit/Makefile.am new file mode 100644 index 0000000..4d213e8 --- /dev/null +++ b/examples/polkit/Makefile.am @@ -0,0 +1,17 @@ +## Copyright (C) 2015 Red Hat, Inc. +## +## This library is free software; you can redistribute it and/or +## modify it under the terms of the GNU Lesser General Public +## License as published by the Free Software Foundation; either +## version 2.1 of the License, or (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public +## License along with this library. If not, see +## <http://www.gnu.org/licenses/>. + +EXTRA_DIST = libvirt-acl.rules diff --git a/examples/polkit/libvirt-acl.rules b/examples/polkit/libvirt-acl.rules new file mode 100644 index 0000000..5c26593 --- /dev/null +++ b/examples/polkit/libvirt-acl.rules @@ -0,0 +1,115 @@ +function Role(name) { + this.name = name; + + this.users = []; + this.groups = []; + + this.check = function(subject, api, domain) { + var validUser = false + + if (this.users.indexOf(subject.user) >= 0) { + validUser = true; + } else { + for (var i = 0; i < subject.groups.length; i++) { + if (this.groups.indexOf(subject.groups[i]) >= 0) { + validUser = true; + break; + } + } + } + + if (validUser && + (this.name == "admin" || + !domain || + (this.domains && domain.match(this.domains)))) { + var msg = "Access granted: " + + "user = " + subject.user + + ", groups = [" + subject.groups + "]" + + ", role = " + this.name + + ", api = " + api; + if (domain) + msg += ", domain = " + domain; + polkit.log(msg); + return true + } + + return false; + }; +} + + +/* Basic operations and monitoring on a limited set of domains. */ +var userA = new Role("userA"); +userA.domains = /^a/; +userA.users = ["userA1", "userA2", "userA3", "multiUser"]; +userA.groups = ["groupA1", "groupA2"]; + +var userB = new Role("userB"); +userB.domains = /^b/; +userB.users = ["userB1", "userB2", "userB3", "multiUser"]; +userB.groups = ["groupB1", "groupB2", "multiGroup"]; + +var userC = new Role("userC"); +userC.domains = /^c/; +userC.users = ["userC1", "userC2", "userC3"]; +userC.groups = ["groupC1", "groupC2", "multiGroup"]; + +/* Same as users but on any domain. */ +var operator = new Role("operator"); +operator.domains = /.*/; +operator.users = ["powerUser1", "powerUser2"]; +operator.groups = ["powerGroup1", "powerGroup2", "powerGroup3"]; + +var users = [operator, userA, userB, userC]; + +/* Full access. */ +var admin = new Role("admin"); +admin.users = ["adminUser1"]; +admin.groups = ["adminGroup1"]; + + +restrictedActions = [ + "domain.core-dump", + "domain.fs-freeze", + "domain.fs-trim", + "domain.getattr", + "domain.hibernate", + "domain.init-control", + "domain.inject-nmi", + "domain.open-device", + "domain.open-graphics", + "domain.pm-control", + "domain.read", + "domain.reset", + "domain.save", + "domain.screenshot", + "domain.send-input", + "domain.send-signal", + "domain.set-password", + "domain.set-time", + "domain.snapshot", + "domain.start", + "domain.stop", + "domain.suspend" +]; + +polkit.addRule(function(action, subject) { + if (action.id.indexOf("org.libvirt.api.") != 0) + return polkit.Result.NOT_HANDLED; + + var api = action.id.replace("org.libvirt.api.", ""); + var domain = action.lookup("domain_name"); + + if (admin.check(subject, api, domain)) + return polkit.Result.YES; + + if (restrictedActions.indexOf(api) < 0) + return polkit.Result.NOT_HANDLED; + + for (var i = 0; i < users.length; i++) { + if (users[i].check(subject, api, domain)) + return polkit.Result.YES; + } + + return polkit.Result.NO; +}); diff --git a/libvirt.spec.in b/libvirt.spec.in index 78a4cc3..6f6b191 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -2039,6 +2039,9 @@ exit 0 %endif # ! %{with_driver_modules} %if %{with_network} + +%doc examples/polkit/*.rules + %files daemon-config-network %defattr(-, root, root) %dir %{_datadir}/libvirt/networks/ -- 2.5.1

On Fri, Sep 04, 2015 at 02:19:09PM +0200, Jiri Denemark wrote:
Creating ACL rules is not exactly easy and existing examples are pretty simple. This patch adds a somewhat complex example which defines several roles. Admins can do everything, operators can do basic operations on any domain and several groups of users who act as operators but only on a limited set of domains.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Makefile.am | 2 +- configure.ac | 1 + examples/polkit/Makefile.am | 17 ++++++ examples/polkit/libvirt-acl.rules | 115 ++++++++++++++++++++++++++++++++++++++ libvirt.spec.in | 3 + 5 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 examples/polkit/Makefile.am create mode 100644 examples/polkit/libvirt-acl.rules
diff --git a/Makefile.am b/Makefile.am index 91b943b..d338d5a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,7 +23,7 @@ SUBDIRS = . gnulib/lib include src daemon tools docs gnulib/tests \ tests po examples/object-events examples/hellolibvirt \ examples/dominfo examples/domsuspend examples/apparmor \ examples/xml/nwfilter examples/openauth examples/systemtap \ - tools/wireshark examples/dommigrate \ + tools/wireshark examples/dommigrate examples/polkit \ examples/lxcconvert examples/domtop
ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index 8471a46..136c2e7 100644 --- a/configure.ac +++ b/configure.ac @@ -2809,6 +2809,7 @@ AC_CONFIG_FILES([\ examples/systemtap/Makefile \ examples/xml/nwfilter/Makefile \ examples/lxcconvert/Makefile \ + examples/polkit/Makefile \ tools/wireshark/Makefile \ tools/wireshark/src/Makefile]) AC_OUTPUT diff --git a/examples/polkit/Makefile.am b/examples/polkit/Makefile.am new file mode 100644 index 0000000..4d213e8 --- /dev/null +++ b/examples/polkit/Makefile.am @@ -0,0 +1,17 @@ +## Copyright (C) 2015 Red Hat, Inc. +## +## This library is free software; you can redistribute it and/or +## modify it under the terms of the GNU Lesser General Public +## License as published by the Free Software Foundation; either +## version 2.1 of the License, or (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public +## License along with this library. If not, see +## <http://www.gnu.org/licenses/>. + +EXTRA_DIST = libvirt-acl.rules diff --git a/examples/polkit/libvirt-acl.rules b/examples/polkit/libvirt-acl.rules new file mode 100644 index 0000000..5c26593 --- /dev/null +++ b/examples/polkit/libvirt-acl.rules @@ -0,0 +1,115 @@
It would be beneficial to put some docs in this file header here to explain to people what this example is achieving.
+function Role(name) { + this.name = name; + + this.users = []; + this.groups = []; + + this.check = function(subject, api, domain) { + var validUser = false + + if (this.users.indexOf(subject.user) >= 0) { + validUser = true; + } else { + for (var i = 0; i < subject.groups.length; i++) { + if (this.groups.indexOf(subject.groups[i]) >= 0) { + validUser = true; + break; + } + } + } + + if (validUser && + (this.name == "admin" || + !domain || + (this.domains && domain.match(this.domains)))) { + var msg = "Access granted: " + + "user = " + subject.user + + ", groups = [" + subject.groups + "]" + + ", role = " + this.name + + ", api = " + api; + if (domain) + msg += ", domain = " + domain; + polkit.log(msg); + return true + } + + return false; + }; +} + + +/* Basic operations and monitoring on a limited set of domains. */ +var userA = new Role("userA"); +userA.domains = /^a/; +userA.users = ["userA1", "userA2", "userA3", "multiUser"]; +userA.groups = ["groupA1", "groupA2"]; + +var userB = new Role("userB"); +userB.domains = /^b/; +userB.users = ["userB1", "userB2", "userB3", "multiUser"]; +userB.groups = ["groupB1", "groupB2", "multiGroup"]; + +var userC = new Role("userC"); +userC.domains = /^c/; +userC.users = ["userC1", "userC2", "userC3"]; +userC.groups = ["groupC1", "groupC2", "multiGroup"]; + +/* Same as users but on any domain. */ +var operator = new Role("operator"); +operator.domains = /.*/; +operator.users = ["powerUser1", "powerUser2"]; +operator.groups = ["powerGroup1", "powerGroup2", "powerGroup3"]; + +var users = [operator, userA, userB, userC]; + +/* Full access. */ +var admin = new Role("admin"); +admin.users = ["adminUser1"]; +admin.groups = ["adminGroup1"]; + + +restrictedActions = [ + "domain.core-dump", + "domain.fs-freeze", + "domain.fs-trim", + "domain.getattr", + "domain.hibernate", + "domain.init-control", + "domain.inject-nmi", + "domain.open-device", + "domain.open-graphics", + "domain.pm-control", + "domain.read", + "domain.reset", + "domain.save", + "domain.screenshot", + "domain.send-input", + "domain.send-signal", + "domain.set-password", + "domain.set-time", + "domain.snapshot", + "domain.start", + "domain.stop", + "domain.suspend" +]; + +polkit.addRule(function(action, subject) { + if (action.id.indexOf("org.libvirt.api.") != 0) + return polkit.Result.NOT_HANDLED; + + var api = action.id.replace("org.libvirt.api.", ""); + var domain = action.lookup("domain_name"); + + if (admin.check(subject, api, domain)) + return polkit.Result.YES; + + if (restrictedActions.indexOf(api) < 0) + return polkit.Result.NOT_HANDLED; + + for (var i = 0; i < users.length; i++) { + if (users[i].check(subject, api, domain)) + return polkit.Result.YES; + } + + return polkit.Result.NO; +}); diff --git a/libvirt.spec.in b/libvirt.spec.in index 78a4cc3..6f6b191 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -2039,6 +2039,9 @@ exit 0 %endif # ! %{with_driver_modules}
%if %{with_network} + +%doc examples/polkit/*.rules + %files daemon-config-network %defattr(-, root, root) %dir %{_datadir}/libvirt/networks/ --
ACK Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Fri, Sep 04, 2015 at 13:26:17 +0100, Daniel P. Berrange wrote:
On Fri, Sep 04, 2015 at 02:19:09PM +0200, Jiri Denemark wrote:
Creating ACL rules is not exactly easy and existing examples are pretty simple. This patch adds a somewhat complex example which defines several roles. Admins can do everything, operators can do basic operations on any domain and several groups of users who act as operators but only on a limited set of domains.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Makefile.am | 2 +- configure.ac | 1 + examples/polkit/Makefile.am | 17 ++++++ examples/polkit/libvirt-acl.rules | 115 ++++++++++++++++++++++++++++++++++++++ libvirt.spec.in | 3 + 5 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 examples/polkit/Makefile.am create mode 100644 examples/polkit/libvirt-acl.rules
diff --git a/Makefile.am b/Makefile.am index 91b943b..d338d5a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,7 +23,7 @@ SUBDIRS = . gnulib/lib include src daemon tools docs gnulib/tests \ tests po examples/object-events examples/hellolibvirt \ examples/dominfo examples/domsuspend examples/apparmor \ examples/xml/nwfilter examples/openauth examples/systemtap \ - tools/wireshark examples/dommigrate \ + tools/wireshark examples/dommigrate examples/polkit \ examples/lxcconvert examples/domtop
ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index 8471a46..136c2e7 100644 --- a/configure.ac +++ b/configure.ac @@ -2809,6 +2809,7 @@ AC_CONFIG_FILES([\ examples/systemtap/Makefile \ examples/xml/nwfilter/Makefile \ examples/lxcconvert/Makefile \ + examples/polkit/Makefile \ tools/wireshark/Makefile \ tools/wireshark/src/Makefile]) AC_OUTPUT diff --git a/examples/polkit/Makefile.am b/examples/polkit/Makefile.am new file mode 100644 index 0000000..4d213e8 --- /dev/null +++ b/examples/polkit/Makefile.am @@ -0,0 +1,17 @@ +## Copyright (C) 2015 Red Hat, Inc. +## +## This library is free software; you can redistribute it and/or +## modify it under the terms of the GNU Lesser General Public +## License as published by the Free Software Foundation; either +## version 2.1 of the License, or (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public +## License along with this library. If not, see +## <http://www.gnu.org/licenses/>. + +EXTRA_DIST = libvirt-acl.rules diff --git a/examples/polkit/libvirt-acl.rules b/examples/polkit/libvirt-acl.rules new file mode 100644 index 0000000..5c26593 --- /dev/null +++ b/examples/polkit/libvirt-acl.rules @@ -0,0 +1,115 @@
It would be beneficial to put some docs in this file header here to explain to people what this example is achieving. ... ACK
Thanks, I added the documentation and pushed this patch. Jirka

On Fri, Sep 04, 2015 at 14:19:09 +0200, Jiri Denemark wrote:
Creating ACL rules is not exactly easy and existing examples are pretty simple. This patch adds a somewhat complex example which defines several roles. Admins can do everything, operators can do basic operations on any domain and several groups of users who act as operators but only on a limited set of domains.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Makefile.am | 2 +- configure.ac | 1 + examples/polkit/Makefile.am | 17 ++++++ examples/polkit/libvirt-acl.rules | 115 ++++++++++++++++++++++++++++++++++++++ libvirt.spec.in | 3 + 5 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 examples/polkit/Makefile.am create mode 100644 examples/polkit/libvirt-acl.rules
Consider the following addition to aclpolkit.html squashed in: diff --git i/docs/aclpolkit.html.in w/docs/aclpolkit.html.in index e5a9b16..dae0814 100644 --- i/docs/aclpolkit.html.in +++ w/docs/aclpolkit.html.in @@ -348,6 +348,12 @@ <code>lookup</code> method. </p> + <p> + See + <a href="http://libvirt.org/git/?p=libvirt.git;a=tree;f=examples/polkit;hb=HEAD">source code</a> + for a more complex example. + </p> + <h3><a name="exconnect">Example: restricting ability to connect to drivers</a></h3> <p> Jirka
participants (2)
-
Daniel P. Berrange
-
Jiri Denemark