Adding support for oslo.rootwrap to namespace access
Changes * adding configuration options for rootwrap * refactoring ssh connection to use rootwrap as a proxy when requested * adding documentation for rootwrap configuration * adding default rootwrap filters file * adding default sudoers conf file for sahara user * adding default rootwrap conf file for sahara-rootwrap * adding sahara-rootwrap cli script * adding requirement for oslo.rootwrap Change-Id: I7871400b2342a4cd1a8910ae5121b1bfdc46078d Closes-Bug: #1271349
This commit is contained in:
parent
4d150db7d5
commit
04502de481
@ -67,3 +67,60 @@ integration see the Sahara documentation sections
|
||||
:ref:`diskimage-builder-label` and :ref:`swift-integration-label`.
|
||||
|
||||
.. _Sahara extra repository: http://github.com/openstack/sahara-extra
|
||||
|
||||
Namespaces and non-root users
|
||||
-----------------------------
|
||||
|
||||
In cases where namespaces are being used to access cluster VMs via private IPs,
|
||||
rootwrap functionality is provided to allow users other than ``root`` access
|
||||
to the namespace related OS facilities. To use rootwrap the following
|
||||
configuration property is required to be set:
|
||||
|
||||
.. sourcecode:: cfg
|
||||
|
||||
[DEFAULT]
|
||||
use_rootwrap=True
|
||||
|
||||
|
||||
Assuming you elect to leverage the default rootwrap command
|
||||
(``sahara-rootwrap``), you will need to perform the following additional setup
|
||||
steps:
|
||||
|
||||
* Copy the provided sudoers configuration file from the local project file
|
||||
``etc/sudoers.d/sahara-rootwrap`` to the system specific location, usually
|
||||
``/etc/sudoers.d``. This file is setup to allow a user named ``sahara``
|
||||
access to the rootwrap script. It contains the following:
|
||||
|
||||
.. sourcecode:: cfg
|
||||
|
||||
sahara ALL = (root) NOPASSWD: /usr/bin/sahara-rootwrap /etc/sahara/rootwrap.conf *
|
||||
|
||||
|
||||
* Copy the provided rootwrap configuration file from the local project file
|
||||
``etc/sahara/rootwrap.conf`` to the system specific location, usually
|
||||
``/etc/sahara``. This file contains the default configuration for rootwrap.
|
||||
|
||||
* Copy the provided rootwrap filers file from the local project file
|
||||
``etc/sahara/rootwrap.d/sahara.filters`` to the location specified in the
|
||||
rootwrap configuration file, usually ``/etc/sahara/rootwrap.d``. This file
|
||||
contains the filters that will allow the ``sahara`` user to acces the
|
||||
``ip netns exec``, ``nc``, and ``kill`` commands through the rootwrap. It
|
||||
should look similar to the followings:
|
||||
|
||||
.. sourcecode:: cfg
|
||||
|
||||
[Filters]
|
||||
ip: IpNetnsExecFilter, ip, root
|
||||
nc: CommandFilter, nc, root
|
||||
kill: CommandFilter, kill, root
|
||||
|
||||
If you wish to use a rootwrap command other than ``sahara-rootwrap`` you can
|
||||
set the following configuration property in your sahara configuration file:
|
||||
|
||||
.. sourcecode:: cfg
|
||||
|
||||
[DEFAULT]
|
||||
rootwrap_command='sudo sahara-rootwrap /etc/sahara/rootwrap.conf'
|
||||
|
||||
For more information on rootwrap please refer to the
|
||||
`official Rootwrap documentation <https://wiki.openstack.org/wiki/Rootwrap>`_
|
||||
|
@ -33,20 +33,26 @@ All volumes are attached during Cluster creation/scaling operations.
|
||||
|
||||
Neutron and Nova Network support
|
||||
--------------------------------
|
||||
OpenStack Cluster may use Nova Network or Neutron as a networking service.
|
||||
Sahara supports both, but when deployed,
|
||||
a special configuration for networking should be set explicitly. By default
|
||||
Sahara will behave as if Nova Network is used.
|
||||
If OpenStack Cluster uses Neutron, then ``use_neutron`` option should be set
|
||||
to ``True`` in Sahara configuration file. In
|
||||
addition, if the OpenStack Cluster supports network namespaces, set the
|
||||
``use_namespaces`` option to ``True``
|
||||
OpenStack clusters may use Nova or Neutron as a networking service. Sahara
|
||||
supports both, but when deployed a special configuration for networking
|
||||
should be set explicitly. By default Sahara will behave as if Nova is used.
|
||||
If an OpenStack cluster uses Neutron, then the ``use_neutron`` property should
|
||||
be set to ``True`` in the Sahara configuration file. Additionally, if the
|
||||
cluster supports network namespaces the ``use_namespaces`` property can be
|
||||
used to enable their usage.
|
||||
|
||||
.. sourcecode:: cfg
|
||||
|
||||
[DEFAULT]
|
||||
use_neutron=True
|
||||
use_namespaces=True
|
||||
|
||||
.. note::
|
||||
If a user other than ``root`` will be running the Sahara server
|
||||
instance and namespaces are used, some additional configuration is
|
||||
required, please see the :doc:`advanced.configuration.guide` for more
|
||||
information.
|
||||
|
||||
Floating IP Management
|
||||
----------------------
|
||||
|
||||
|
34
etc/sahara/rootwrap.conf
Normal file
34
etc/sahara/rootwrap.conf
Normal file
@ -0,0 +1,34 @@
|
||||
# Configuration for sahara-rootwrap
|
||||
# This file should be owned by (and only-writeable by) the root user
|
||||
|
||||
[DEFAULT]
|
||||
# List of directories to load filter definitions from (separated by ',').
|
||||
# These directories MUST all be only writeable by root !
|
||||
filters_path=/etc/sahara/rootwrap.d
|
||||
|
||||
# List of directories to search executables in, in case filters do not
|
||||
# explicitely specify a full path (separated by ',')
|
||||
# If not specified, defaults to system PATH environment variable.
|
||||
# These directories MUST all be only writeable by root !
|
||||
exec_dirs=/sbin,/usr/sbin,/bin,/usr/bin
|
||||
|
||||
# Enable logging to syslog
|
||||
# Default value is False
|
||||
use_syslog=False
|
||||
|
||||
# Which syslog facility to use.
|
||||
# Valid values include auth, authpriv, syslog, local0, local1...
|
||||
# Default value is 'syslog'
|
||||
syslog_log_facility=syslog
|
||||
|
||||
# Which messages to log.
|
||||
# INFO means log all usage
|
||||
# ERROR means only log unsuccessful attempts
|
||||
syslog_log_level=ERROR
|
||||
|
||||
[xenapi]
|
||||
# XenAPI configuration is only required by the L2 agent if it is to
|
||||
# target a XenServer/XCP compute host's dom0.
|
||||
xenapi_connection_url=<None>
|
||||
xenapi_connection_username=root
|
||||
xenapi_connection_password=<None>
|
4
etc/sahara/rootwrap.d/sahara.filters
Normal file
4
etc/sahara/rootwrap.d/sahara.filters
Normal file
@ -0,0 +1,4 @@
|
||||
[Filters]
|
||||
ip: IpNetnsExecFilter, ip, root
|
||||
nc: CommandFilter, nc, root
|
||||
kill: CommandFilter, kill, root
|
@ -224,6 +224,16 @@
|
||||
# in conjunction with use_neutron=True). (boolean value)
|
||||
#use_namespaces=false
|
||||
|
||||
# Use rootwrap facility to allow non-root users to run the
|
||||
# sahara-all server instance and access private network IPs
|
||||
# (only valid to use in conjunction with use_namespaces=True)
|
||||
# (boolean value)
|
||||
#use_rootwrap=false
|
||||
|
||||
# Rootwrap command to leverage. Use in conjunction with
|
||||
# use_rootwrap=True (string value)
|
||||
#rootwrap_command=sudo sahara-rootwrap /etc/sahara/rootwrap.conf
|
||||
|
||||
|
||||
#
|
||||
# Options defined in sahara.main
|
||||
|
1
etc/sudoers.d/sahara-rootwrap
Normal file
1
etc/sudoers.d/sahara-rootwrap
Normal file
@ -0,0 +1 @@
|
||||
sahara ALL=(root) NOPASSWD: /usr/bin/sahara-rootwrap /etc/sahara/rootwrap.conf *
|
@ -16,6 +16,7 @@ oslo.config>=1.4.0 # Apache-2.0
|
||||
oslo.db>=1.0.0 # Apache-2.0
|
||||
oslo.i18n>=1.0.0 # Apache-2.0
|
||||
oslo.messaging>=1.4.0
|
||||
oslo.rootwrap>=1.3.0
|
||||
oslo.serialization>=1.0.0 # Apache-2.0
|
||||
oslo.utils>=1.0.0 # Apache-2.0
|
||||
paramiko>=1.13.0
|
||||
|
21
sahara/cli/sahara_rootwrap.py
Executable file
21
sahara/cli/sahara_rootwrap.py
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2014 OpenStack Foundation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo.rootwrap import cmd
|
||||
|
||||
|
||||
def main():
|
||||
cmd.main()
|
@ -59,7 +59,17 @@ networking_opts = [
|
||||
cfg.BoolOpt('use_namespaces',
|
||||
default=False,
|
||||
help="Use network namespaces for communication (only valid to "
|
||||
"use in conjunction with use_neutron=True).")
|
||||
"use in conjunction with use_neutron=True)."),
|
||||
cfg.BoolOpt('use_rootwrap',
|
||||
default=False,
|
||||
help="Use rootwrap facility to allow non-root users to run "
|
||||
"the sahara-all server instance and access private "
|
||||
"network IPs (only valid to use in conjunction with "
|
||||
"use_namespaces=True)"),
|
||||
cfg.StrOpt('rootwrap_command',
|
||||
default='sudo sahara-rootwrap /etc/sahara/rootwrap.conf',
|
||||
help="Rootwrap command to leverage. Use in conjunction with "
|
||||
"use_rootwrap=True")
|
||||
]
|
||||
|
||||
|
||||
|
@ -80,15 +80,20 @@ class NeutronClientRemoteWrapper():
|
||||
|
||||
return matching_router['id']
|
||||
|
||||
def get_http_session(self, host, port=None, *args, **kwargs):
|
||||
def get_http_session(self, host, port=None, use_rootwrap=False,
|
||||
rootwrap_command=None, *args, **kwargs):
|
||||
session = requests.Session()
|
||||
adapters = self._get_adapters(host, port=port, *args, **kwargs)
|
||||
adapters = self._get_adapters(host, port=port,
|
||||
use_rootwrap=use_rootwrap,
|
||||
rootwrap_command=rootwrap_command,
|
||||
*args, **kwargs)
|
||||
for adapter in adapters:
|
||||
session.mount('http://{0}:{1}'.format(host, adapter.port), adapter)
|
||||
|
||||
return session
|
||||
|
||||
def _get_adapters(self, host, port=None, *args, **kwargs):
|
||||
def _get_adapters(self, host, port=None, use_rootwrap=False,
|
||||
rootwrap_command=None, *args, **kwargs):
|
||||
LOG.debug('Retrieving neutron adapters for {0}:{1}'.format(host, port))
|
||||
adapters = []
|
||||
if not port:
|
||||
@ -103,7 +108,9 @@ class NeutronClientRemoteWrapper():
|
||||
.format(host, port))
|
||||
qrouter = self.get_router()
|
||||
adapter = (
|
||||
NeutronHttpAdapter(qrouter, host, port))
|
||||
NeutronHttpAdapter(qrouter, host, port,
|
||||
use_rootwrap=use_rootwrap,
|
||||
rootwrap_command=rootwrap_command))
|
||||
self.adapters[(host, port)] = adapter
|
||||
adapters = [adapter]
|
||||
|
||||
@ -114,14 +121,17 @@ class NeutronHttpAdapter(adapters.HTTPAdapter):
|
||||
port = None
|
||||
host = None
|
||||
|
||||
def __init__(self, qrouter, host, port, *args, **kwargs):
|
||||
def __init__(self, qrouter, host, port, use_rootwrap=False,
|
||||
rootwrap_command=None, *args, **kwargs):
|
||||
super(NeutronHttpAdapter, self).__init__(*args, **kwargs)
|
||||
command = 'ip netns exec qrouter-{0} nc {1} {2}'.format(qrouter,
|
||||
host, port)
|
||||
command = '{0} ip netns exec qrouter-{1} nc {2} {3}'.format(
|
||||
rootwrap_command if use_rootwrap else '',
|
||||
qrouter, host, port)
|
||||
LOG.debug('Neutron adapter created with cmd {0}'.format(command))
|
||||
self.cmd = shlex.split(command)
|
||||
self.port = port
|
||||
self.host = host
|
||||
self.rootwrap_command = rootwrap_command if use_rootwrap else None
|
||||
|
||||
def get_connection(self, url, proxies=None):
|
||||
pool_conn = (
|
||||
@ -152,7 +162,7 @@ class NeutronHttpAdapter(adapters.HTTPAdapter):
|
||||
def _connect(self):
|
||||
LOG.debug('returning netcat socket with command {0}'
|
||||
.format(self.cmd))
|
||||
return NetcatSocket(self.cmd)
|
||||
return NetcatSocket(self.cmd, rootwrap_command=self.rootwrap_command)
|
||||
|
||||
|
||||
class NetcatSocket:
|
||||
@ -163,8 +173,9 @@ class NetcatSocket:
|
||||
stdout=e_subprocess.PIPE,
|
||||
stderr=e_subprocess.PIPE)
|
||||
|
||||
def __init__(self, cmd):
|
||||
def __init__(self, cmd, rootwrap_command=None):
|
||||
self.cmd = cmd
|
||||
self.rootwrap_command = rootwrap_command
|
||||
self._create_process()
|
||||
|
||||
def send(self, content):
|
||||
@ -191,7 +202,11 @@ class NetcatSocket:
|
||||
raise ex.SystemError(e)
|
||||
|
||||
def _terminate(self):
|
||||
self.process.terminate()
|
||||
if self.rootwrap_command:
|
||||
os.system('{0} kill {1}'.format(self.rootwrap_command,
|
||||
self.process.pid))
|
||||
else:
|
||||
self.process.terminate()
|
||||
|
||||
def close(self):
|
||||
LOG.debug('Socket close called')
|
||||
|
@ -75,8 +75,11 @@ def _get_proxy(neutron_info):
|
||||
neutron_info['token'],
|
||||
neutron_info['tenant'])
|
||||
qrouter = client.get_router()
|
||||
proxy = paramiko.ProxyCommand('ip netns exec qrouter-{0} nc {1} 22'
|
||||
.format(qrouter, neutron_info['host']))
|
||||
proxy = paramiko.ProxyCommand('{0} ip netns exec qrouter-{1} nc {2} 22'
|
||||
.format(neutron_info['rootwrap_command']
|
||||
if neutron_info['use_rootwrap']
|
||||
else '',
|
||||
qrouter, neutron_info['host']))
|
||||
|
||||
return proxy
|
||||
|
||||
@ -158,7 +161,8 @@ def _get_http_client(host, port, neutron_info, *args, **kwargs):
|
||||
# the same adapter (and same connection pools) for a given
|
||||
# host and port tuple
|
||||
_http_session = neutron_client.get_http_session(
|
||||
host, port=port, *args, **kwargs)
|
||||
host, port=port, use_rootwrap=CONF.use_rootwrap,
|
||||
rootwrap_command=CONF.rootwrap_command, *args, **kwargs)
|
||||
LOG.debug('created neutron based HTTP session for {0}:{1}'
|
||||
.format(host, port))
|
||||
else:
|
||||
@ -336,6 +340,8 @@ class InstanceInteropHelper(remote.Remote):
|
||||
neutron_info['token'] = ctx.token
|
||||
neutron_info['tenant'] = ctx.tenant_name
|
||||
neutron_info['host'] = self.instance.management_ip
|
||||
neutron_info['use_rootwrap'] = CONF.use_rootwrap
|
||||
neutron_info['rootwrap_command'] = CONF.rootwrap_command
|
||||
|
||||
LOG.debug('Returning neutron info: {0}'.format(neutron_info))
|
||||
return neutron_info
|
||||
|
@ -33,6 +33,7 @@ console_scripts =
|
||||
sahara-api = sahara.cli.sahara_api:main
|
||||
sahara-engine = sahara.cli.sahara_engine:main
|
||||
sahara-db-manage = sahara.db.migration.cli:main
|
||||
sahara-rootwrap = sahara.cli.sahara_rootwrap:main
|
||||
_sahara-subprocess = sahara.cli.sahara_subprocess:main
|
||||
|
||||
sahara.cluster.plugins =
|
||||
|
Loading…
x
Reference in New Issue
Block a user