
Currently, every user with sudo permissions can perform any operation on any virtual machine.
In order to add more security, Kimchi will only allow users listed in the VM metadata - along with those with sudo permissions - to be able to perform actions on it. A VM may contain a list of system users and groups associated with it. If a user is not listed to access a VM, they will not be able to see it or to perform any operation on it.
Signed-off-by: Crístian Viana <vianac@linux.vnet.ibm.com> --- src/kimchi/control/base.py | 4 +++ src/kimchi/model/vms.py | 63 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 2 deletions(-)
diff --git a/src/kimchi/control/base.py b/src/kimchi/control/base.py index f8a5210..6022472 100644 --- a/src/kimchi/control/base.py +++ b/src/kimchi/control/base.py @@ -118,6 +118,10 @@ class Resource(object):
@cherrypy.expose def index(self): + authorized = getattr(self.model, model_fn(self, 'is_authorized'), None) + if authorized is not None and not authorized(*self.model_args): + raise cherrypy.HTTPError(403) + method = validate_method(('GET', 'DELETE', 'PUT')) try: return {'GET': self.get, diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index 17bda04..00dcd0f 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -19,16 +19,19 @@
from lxml.builder import E import lxml.etree as ET +import grp import os import time import uuid from xml.etree import ElementTree
+import cherrypy import libvirt from cherrypy.process.plugins import BackgroundTask
from kimchi import vnc from kimchi import xmlutils +from kimchi.auth import USER_NAME, USER_SUDO from kimchi.config import READONLY_POOL_TYPE from kimchi.exception import InvalidOperation, InvalidParameter from kimchi.exception import NotFoundError, OperationFailed @@ -232,8 +235,8 @@ class VMsModel(object):
@staticmethod def get_vms(conn): - conn = conn.get() - names = [dom.name().decode('utf-8') for dom in conn.listAllDomains(0)] + libvirtconn = conn.get() + names = [dom.name().decode('utf-8') for dom in libvirtconn.listAllDomains(0) if VMModel._vm_is_authorized(dom.name(), conn)] Filtering resources here can work, while I suggest using filter resources in controller to be more generic, cover all resources will filter logic. In model all resources report a 'users' information in its data()--means
On 2014年07月12日 03:08, Crístian Viana wrote: the valid user to view this resource: vm--{'users':["kimchi_user_1", "root"]} In controller, base.py: def filter_data(): user_name = cherrypy.session.get(USER_NAME, None) data = [] for res in resources: if all(key in res.data and res.data[key] == val and user_name in data["user"] for key, val in fields_filter.iteritems()): data.append(res.data) return data
return sorted(names, key=unicode.lower)
@@ -526,6 +529,62 @@ class VMModel(object): kimchi_log.error('Error trying to delete vm screenshot from ' 'database due error: %s', e.message)
+ @staticmethod + def _vm_get_access_users(name, conn): + dom = conn.get().lookupByName(name) + metadata = get_metadata_node(dom, 'access') + if metadata == '': + return [] + + users_xml = ET.fromstring(metadata).find('user') + return [] if users_xml is None else [ users_xml.text ] + + @staticmethod + def _vm_get_access_groups(name, conn): + dom = conn.get().lookupByName(name) + metadata = get_metadata_node(dom, 'access') + if metadata == '': + return [] + + groups_xml = ET.fromstring(metadata).find('group') + return [] if groups_xml is None else [ groups_xml.text ] + + @staticmethod + def _vm_is_authorized(name, conn): + try: + user_name = cherrypy.session.get(USER_NAME, None) + user_sudo = cherrypy.session.get(USER_SUDO, False) + except AttributeError: + return False + + if user_sudo: + return True + + dom = conn.get().lookupByName(name) + metadata = get_metadata_node(dom, 'access') + + if user_name is None or metadata == '': + return True + + users = VMModel._vm_get_access_users(name, conn) + groups = VMModel._vm_get_access_groups(name, conn) + + users_in_groups = set() + for vm_g in groups: + try: + for u in grp.getgrnam(vm_g).gr_mem: + users_in_groups.add(u) + except KeyError: + kimchi_log.warning("group '%s' is listed as authorized by VM '%s' but it doesn't exist" + % (vm_g, name)) + + if user_name in users or user_name in users_in_groups: + return True + + return False + + def is_authorized(self, name): + return VMModel._vm_is_authorized(name, self.conn)
class VMScreenshotModel(object): def __init__(self, **kargs):