[Kimchi-devel] [WIP] Filter VMs by users and groups

Aline Manera alinefm at linux.vnet.ibm.com
Wed Jul 16 15:17:06 UTC 2014


On 07/16/2014 05:32 AM, Royce Lv wrote:
> On 2014年07月12日 03:08, Crístian Viana wrote:
>> 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 at 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 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
>

Good suggestion, Royce!
It makes the logic simpler and easier to use

>>           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):
>
> _______________________________________________
> Kimchi-devel mailing list
> Kimchi-devel at ovirt.org
> http://lists.ovirt.org/mailman/listinfo/kimchi-devel




More information about the Kimchi-devel mailing list