Allow metadata proxy running with nobody user/group
Currently metadata proxy cannot run with nobody user/group as metadata proxy requires to connect to metadata_proxy_socket when queried. This change allows to run metadata proxy with nobody user/group by allowing to choose the metadata_proxy_socket mode with the new option metadata_proxy_socket_mode (4 choices) in order to adapt socket permissions to metadata proxy user/group. This change refactors also where options are defined to enable metadata_proxy_user/group options in the metadata agent. In practice: * if metadata_proxy_user is agent effective user or root, then: * metadata proxy is allowed to use rootwrap (unsecure) * set metadata_proxy_socket_mode = user (0o644) * else if metadata_proxy_group is agent effective group, then: * metadata proxy is not allowed to use rootwrap (secure) * set metadata_proxy_socket_mode = group (0o664) * set metadata_proxy_log_watch = false * else: * metadata proxy has lowest permissions (securest) but metadata proxy socket can be opened by everyone * set metadata_proxy_socket_mode = all (0o666) * set metadata_proxy_log_watch = false An alternative is to set metadata_proxy_socket_mode = deduce, in such case metadata agent uses previous rules to choose the correct mode. DocImpact Closes-Bug: #1427228 Change-Id: I235a0cc4f0cbd55ae4ec1570daf2ebbb6a72441d
This commit is contained in:
parent
aa943f930d
commit
80bea7a386
@ -45,6 +45,15 @@ admin_password = %SERVICE_PASSWORD%
|
|||||||
# Location of Metadata Proxy UNIX domain socket
|
# Location of Metadata Proxy UNIX domain socket
|
||||||
# metadata_proxy_socket = $state_path/metadata_proxy
|
# metadata_proxy_socket = $state_path/metadata_proxy
|
||||||
|
|
||||||
|
# Metadata Proxy UNIX domain socket mode, 3 values allowed:
|
||||||
|
# 'deduce': deduce mode from metadata_proxy_user/group values,
|
||||||
|
# 'user': set metadata proxy socket mode to 0o644, to use when
|
||||||
|
# metadata_proxy_user is agent effective user or root,
|
||||||
|
# 'group': set metadata proxy socket mode to 0o664, to use when
|
||||||
|
# metadata_proxy_group is agent effective group,
|
||||||
|
# 'all': set metadata proxy socket mode to 0o666, to use otherwise.
|
||||||
|
# metadata_proxy_socket_mode = deduce
|
||||||
|
|
||||||
# Number of separate worker processes for metadata server. Defaults to
|
# Number of separate worker processes for metadata server. Defaults to
|
||||||
# half the number of CPU cores
|
# half the number of CPU cores
|
||||||
# metadata_workers =
|
# metadata_workers =
|
||||||
|
@ -21,7 +21,7 @@ from oslo_config import cfg
|
|||||||
from neutron.agent.common import config
|
from neutron.agent.common import config
|
||||||
from neutron.agent.dhcp import config as dhcp_config
|
from neutron.agent.dhcp import config as dhcp_config
|
||||||
from neutron.agent.linux import interface
|
from neutron.agent.linux import interface
|
||||||
from neutron.agent.metadata import driver as metadata_driver
|
from neutron.agent.metadata import config as metadata_config
|
||||||
from neutron.common import config as common_config
|
from neutron.common import config as common_config
|
||||||
from neutron.common import topics
|
from neutron.common import topics
|
||||||
from neutron.openstack.common import service
|
from neutron.openstack.common import service
|
||||||
@ -35,7 +35,8 @@ def register_options():
|
|||||||
cfg.CONF.register_opts(dhcp_config.DHCP_AGENT_OPTS)
|
cfg.CONF.register_opts(dhcp_config.DHCP_AGENT_OPTS)
|
||||||
cfg.CONF.register_opts(dhcp_config.DHCP_OPTS)
|
cfg.CONF.register_opts(dhcp_config.DHCP_OPTS)
|
||||||
cfg.CONF.register_opts(dhcp_config.DNSMASQ_OPTS)
|
cfg.CONF.register_opts(dhcp_config.DNSMASQ_OPTS)
|
||||||
cfg.CONF.register_opts(metadata_driver.MetadataDriver.OPTS)
|
cfg.CONF.register_opts(metadata_config.DRIVER_OPTS)
|
||||||
|
cfg.CONF.register_opts(metadata_config.SHARED_OPTS)
|
||||||
cfg.CONF.register_opts(interface.OPTS)
|
cfg.CONF.register_opts(interface.OPTS)
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ from neutron.agent.l3 import config as l3_config
|
|||||||
from neutron.agent.l3 import ha
|
from neutron.agent.l3 import ha
|
||||||
from neutron.agent.linux import external_process
|
from neutron.agent.linux import external_process
|
||||||
from neutron.agent.linux import interface
|
from neutron.agent.linux import interface
|
||||||
from neutron.agent.metadata import driver as metadata_driver
|
from neutron.agent.metadata import config as metadata_config
|
||||||
from neutron.common import config as common_config
|
from neutron.common import config as common_config
|
||||||
from neutron.common import topics
|
from neutron.common import topics
|
||||||
from neutron.openstack.common import service
|
from neutron.openstack.common import service
|
||||||
@ -32,7 +32,8 @@ from neutron import service as neutron_service
|
|||||||
|
|
||||||
def register_opts(conf):
|
def register_opts(conf):
|
||||||
conf.register_opts(l3_config.OPTS)
|
conf.register_opts(l3_config.OPTS)
|
||||||
conf.register_opts(metadata_driver.MetadataDriver.OPTS)
|
conf.register_opts(metadata_config.DRIVER_OPTS)
|
||||||
|
conf.register_opts(metadata_config.SHARED_OPTS)
|
||||||
conf.register_opts(ha.OPTS)
|
conf.register_opts(ha.OPTS)
|
||||||
config.register_interface_driver_opts_helper(conf)
|
config.register_interface_driver_opts_helper(conf)
|
||||||
config.register_use_namespaces_opts_helper(conf)
|
config.register_use_namespaces_opts_helper(conf)
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
import fcntl
|
import fcntl
|
||||||
import glob
|
import glob
|
||||||
|
import grp
|
||||||
import httplib
|
import httplib
|
||||||
import os
|
import os
|
||||||
import pwd
|
import pwd
|
||||||
@ -344,6 +345,15 @@ def is_effective_user(user_id_or_name):
|
|||||||
return user_id_or_name == effective_user_name
|
return user_id_or_name == effective_user_name
|
||||||
|
|
||||||
|
|
||||||
|
def is_effective_group(group_id_or_name):
|
||||||
|
"""Returns True if group_id_or_name is effective group (id/name)."""
|
||||||
|
egid = os.getegid()
|
||||||
|
if str(group_id_or_name) == str(egid):
|
||||||
|
return True
|
||||||
|
effective_group_name = grp.getgrgid(egid).gr_name
|
||||||
|
return group_id_or_name == effective_group_name
|
||||||
|
|
||||||
|
|
||||||
class UnixDomainHTTPConnection(httplib.HTTPConnection):
|
class UnixDomainHTTPConnection(httplib.HTTPConnection):
|
||||||
"""Connection class for HTTP over UNIX domain socket."""
|
"""Connection class for HTTP over UNIX domain socket."""
|
||||||
def __init__(self, host, port=None, strict=None, timeout=None,
|
def __init__(self, host, port=None, strict=None, timeout=None,
|
||||||
@ -375,10 +385,12 @@ class UnixDomainWSGIServer(wsgi.Server):
|
|||||||
self._server = None
|
self._server = None
|
||||||
super(UnixDomainWSGIServer, self).__init__(name)
|
super(UnixDomainWSGIServer, self).__init__(name)
|
||||||
|
|
||||||
def start(self, application, file_socket, workers, backlog):
|
def start(self, application, file_socket, workers, backlog, mode=None):
|
||||||
self._socket = eventlet.listen(file_socket,
|
self._socket = eventlet.listen(file_socket,
|
||||||
family=socket.AF_UNIX,
|
family=socket.AF_UNIX,
|
||||||
backlog=backlog)
|
backlog=backlog)
|
||||||
|
if mode is not None:
|
||||||
|
os.chmod(file_socket, mode)
|
||||||
|
|
||||||
self._launch(application, workers=workers)
|
self._launch(application, workers=workers)
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import six.moves.urllib.parse as urlparse
|
|||||||
import webob
|
import webob
|
||||||
|
|
||||||
from neutron.agent.linux import utils as agent_utils
|
from neutron.agent.linux import utils as agent_utils
|
||||||
|
from neutron.agent.metadata import config
|
||||||
from neutron.agent import rpc as agent_rpc
|
from neutron.agent import rpc as agent_rpc
|
||||||
from neutron.common import constants as n_const
|
from neutron.common import constants as n_const
|
||||||
from neutron.common import rpc as n_rpc
|
from neutron.common import rpc as n_rpc
|
||||||
@ -36,6 +37,12 @@ from neutron.openstack.common import loopingcall
|
|||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
MODE_MAP = {
|
||||||
|
config.USER_MODE: 0o644,
|
||||||
|
config.GROUP_MODE: 0o664,
|
||||||
|
config.ALL_MODE: 0o666,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class MetadataPluginAPI(object):
|
class MetadataPluginAPI(object):
|
||||||
"""Agent-side RPC for metadata agent-to-plugin interaction.
|
"""Agent-side RPC for metadata agent-to-plugin interaction.
|
||||||
@ -305,10 +312,29 @@ class UnixDomainMetadataProxy(object):
|
|||||||
return
|
return
|
||||||
self.agent_state.pop('start_flag', None)
|
self.agent_state.pop('start_flag', None)
|
||||||
|
|
||||||
|
def _get_socket_mode(self):
|
||||||
|
mode = self.conf.metadata_proxy_socket_mode
|
||||||
|
if mode == config.DEDUCE_MODE:
|
||||||
|
user = self.conf.metadata_proxy_user
|
||||||
|
if (not user or user == '0' or user == 'root'
|
||||||
|
or agent_utils.is_effective_user(user)):
|
||||||
|
# user is agent effective user or root => USER_MODE
|
||||||
|
mode = config.USER_MODE
|
||||||
|
else:
|
||||||
|
group = self.conf.metadata_proxy_group
|
||||||
|
if not group or agent_utils.is_effective_group(group):
|
||||||
|
# group is agent effective group => GROUP_MODE
|
||||||
|
mode = config.GROUP_MODE
|
||||||
|
else:
|
||||||
|
# otherwise => ALL_MODE
|
||||||
|
mode = config.ALL_MODE
|
||||||
|
return MODE_MAP[mode]
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
server = agent_utils.UnixDomainWSGIServer('neutron-metadata-agent')
|
server = agent_utils.UnixDomainWSGIServer('neutron-metadata-agent')
|
||||||
server.start(MetadataProxyHandler(self.conf),
|
server.start(MetadataProxyHandler(self.conf),
|
||||||
self.conf.metadata_proxy_socket,
|
self.conf.metadata_proxy_socket,
|
||||||
workers=self.conf.metadata_workers,
|
workers=self.conf.metadata_workers,
|
||||||
backlog=self.conf.metadata_backlog)
|
backlog=self.conf.metadata_backlog,
|
||||||
|
mode=self._get_socket_mode())
|
||||||
server.wait()
|
server.wait()
|
||||||
|
@ -17,6 +17,38 @@ from oslo_config import cfg
|
|||||||
from neutron.common import utils
|
from neutron.common import utils
|
||||||
|
|
||||||
|
|
||||||
|
SHARED_OPTS = [
|
||||||
|
cfg.StrOpt('metadata_proxy_socket',
|
||||||
|
default='$state_path/metadata_proxy',
|
||||||
|
help=_('Location for Metadata Proxy UNIX domain socket.')),
|
||||||
|
cfg.StrOpt('metadata_proxy_user',
|
||||||
|
default='',
|
||||||
|
help=_("User (uid or name) running metadata proxy after "
|
||||||
|
"its initialization (if empty: agent effective "
|
||||||
|
"user).")),
|
||||||
|
cfg.StrOpt('metadata_proxy_group',
|
||||||
|
default='',
|
||||||
|
help=_("Group (gid or name) running metadata proxy after "
|
||||||
|
"its initialization (if empty: agent effective "
|
||||||
|
"group)."))
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
DRIVER_OPTS = [
|
||||||
|
cfg.BoolOpt('metadata_proxy_watch_log',
|
||||||
|
default=None,
|
||||||
|
help=_("Enable/Disable log watch by metadata proxy. It "
|
||||||
|
"should be disabled when metadata_proxy_user/group "
|
||||||
|
"is not allowed to read/write its log file and "
|
||||||
|
"copytruncate logrotate option must be used if "
|
||||||
|
"logrotate is enabled on metadata proxy log "
|
||||||
|
"files. Option default value is deduced from "
|
||||||
|
"metadata_proxy_user: watch log is enabled if "
|
||||||
|
"metadata_proxy_user is agent effective user "
|
||||||
|
"id/name.")),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
METADATA_PROXY_HANDLER_OPTS = [
|
METADATA_PROXY_HANDLER_OPTS = [
|
||||||
cfg.StrOpt('admin_user',
|
cfg.StrOpt('admin_user',
|
||||||
help=_("Admin user")),
|
help=_("Admin user")),
|
||||||
@ -66,11 +98,29 @@ METADATA_PROXY_HANDLER_OPTS = [
|
|||||||
help=_("Private key of client certificate."))
|
help=_("Private key of client certificate."))
|
||||||
]
|
]
|
||||||
|
|
||||||
|
DEDUCE_MODE = 'deduce'
|
||||||
|
USER_MODE = 'user'
|
||||||
|
GROUP_MODE = 'group'
|
||||||
|
ALL_MODE = 'all'
|
||||||
|
SOCKET_MODES = (DEDUCE_MODE, USER_MODE, GROUP_MODE, ALL_MODE)
|
||||||
|
|
||||||
|
|
||||||
UNIX_DOMAIN_METADATA_PROXY_OPTS = [
|
UNIX_DOMAIN_METADATA_PROXY_OPTS = [
|
||||||
cfg.StrOpt('metadata_proxy_socket',
|
cfg.StrOpt('metadata_proxy_socket_mode',
|
||||||
default='$state_path/metadata_proxy',
|
default=DEDUCE_MODE,
|
||||||
help=_('Location for Metadata Proxy UNIX domain socket')),
|
choices=SOCKET_MODES,
|
||||||
|
help=_("Metadata Proxy UNIX domain socket mode, 3 values "
|
||||||
|
"allowed: "
|
||||||
|
"'deduce': deduce mode from metadata_proxy_user/group "
|
||||||
|
"values, "
|
||||||
|
"'user': set metadata proxy socket mode to 0o644, to "
|
||||||
|
"use when metadata_proxy_user is agent effective user "
|
||||||
|
"or root, "
|
||||||
|
"'group': set metadata proxy socket mode to 0o664, to "
|
||||||
|
"use when metadata_proxy_group is agent effective "
|
||||||
|
"group or root, "
|
||||||
|
"'all': set metadata proxy socket mode to 0o666, to use "
|
||||||
|
"otherwise.")),
|
||||||
cfg.IntOpt('metadata_workers',
|
cfg.IntOpt('metadata_workers',
|
||||||
default=utils.cpu_count() // 2,
|
default=utils.cpu_count() // 2,
|
||||||
help=_('Number of separate worker processes for metadata '
|
help=_('Number of separate worker processes for metadata '
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from neutron.agent.common import config
|
from neutron.agent.common import config
|
||||||
@ -36,34 +35,6 @@ METADATA_SERVICE_NAME = 'metadata-proxy'
|
|||||||
|
|
||||||
class MetadataDriver(object):
|
class MetadataDriver(object):
|
||||||
|
|
||||||
OPTS = [
|
|
||||||
cfg.StrOpt('metadata_proxy_socket',
|
|
||||||
default='$state_path/metadata_proxy',
|
|
||||||
help=_('Location of Metadata Proxy UNIX domain '
|
|
||||||
'socket')),
|
|
||||||
cfg.StrOpt('metadata_proxy_user',
|
|
||||||
default='',
|
|
||||||
help=_("User (uid or name) running metadata proxy after "
|
|
||||||
"its initialization (if empty: agent effective "
|
|
||||||
"user)")),
|
|
||||||
cfg.StrOpt('metadata_proxy_group',
|
|
||||||
default='',
|
|
||||||
help=_("Group (gid or name) running metadata proxy after "
|
|
||||||
"its initialization (if empty: agent effective "
|
|
||||||
"group)")),
|
|
||||||
cfg.BoolOpt('metadata_proxy_watch_log',
|
|
||||||
default=None,
|
|
||||||
help=_("Enable/Disable log watch by metadata proxy. It "
|
|
||||||
"should be disabled when metadata_proxy_user/group "
|
|
||||||
"is not allowed to read/write its log file and "
|
|
||||||
"copytruncate logrotate option must be used if "
|
|
||||||
"logrotate is enabled on metadata proxy log "
|
|
||||||
"files. Option default value is deduced from "
|
|
||||||
"metadata_proxy_user: watch log is enabled if "
|
|
||||||
"metadata_proxy_user is agent effective user "
|
|
||||||
"id/name.")),
|
|
||||||
]
|
|
||||||
|
|
||||||
def __init__(self, l3_agent):
|
def __init__(self, l3_agent):
|
||||||
self.metadata_port = l3_agent.conf.metadata_port
|
self.metadata_port = l3_agent.conf.metadata_port
|
||||||
self.metadata_access_mark = l3_agent.conf.metadata_access_mark
|
self.metadata_access_mark = l3_agent.conf.metadata_access_mark
|
||||||
|
@ -28,6 +28,7 @@ LOG = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
cfg.CONF.register_opts(metadata_conf.SHARED_OPTS)
|
||||||
cfg.CONF.register_opts(metadata_conf.UNIX_DOMAIN_METADATA_PROXY_OPTS)
|
cfg.CONF.register_opts(metadata_conf.UNIX_DOMAIN_METADATA_PROXY_OPTS)
|
||||||
cfg.CONF.register_opts(metadata_conf.METADATA_PROXY_HANDLER_OPTS)
|
cfg.CONF.register_opts(metadata_conf.METADATA_PROXY_HANDLER_OPTS)
|
||||||
cache.register_oslo_configs(cfg.CONF)
|
cache.register_oslo_configs(cfg.CONF)
|
||||||
|
@ -20,6 +20,8 @@ import select
|
|||||||
import shlex
|
import shlex
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
import fixtures
|
||||||
|
|
||||||
from neutron.agent.common import config
|
from neutron.agent.common import config
|
||||||
from neutron.agent.linux import ip_lib
|
from neutron.agent.linux import ip_lib
|
||||||
from neutron.agent.linux import utils
|
from neutron.agent.linux import utils
|
||||||
@ -33,6 +35,33 @@ SS_SOURCE_PORT_PATTERN = re.compile(
|
|||||||
r'^.*\s+\d+\s+.*:(?P<port>\d+)\s+[0-9:].*')
|
r'^.*\s+\d+\s+.*:(?P<port>\d+)\s+[0-9:].*')
|
||||||
|
|
||||||
|
|
||||||
|
class RecursivePermDirFixture(fixtures.Fixture):
|
||||||
|
"""Ensure at least perms permissions on directory and ancestors."""
|
||||||
|
|
||||||
|
def __init__(self, directory, perms):
|
||||||
|
super(RecursivePermDirFixture, self).__init__()
|
||||||
|
self.directory = directory
|
||||||
|
self.least_perms = perms
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(RecursivePermDirFixture, self).setUp()
|
||||||
|
previous_directory = None
|
||||||
|
current_directory = self.directory
|
||||||
|
while previous_directory != current_directory:
|
||||||
|
perms = os.stat(current_directory).st_mode
|
||||||
|
if perms & self.least_perms != self.least_perms:
|
||||||
|
os.chmod(current_directory, perms | self.least_perms)
|
||||||
|
self.addCleanup(self.safe_chmod, current_directory, perms)
|
||||||
|
previous_directory = current_directory
|
||||||
|
current_directory = os.path.dirname(current_directory)
|
||||||
|
|
||||||
|
def safe_chmod(self, path, mode):
|
||||||
|
try:
|
||||||
|
os.chmod(path, mode)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def get_free_namespace_port(tcp=True, namespace=None):
|
def get_free_namespace_port(tcp=True, namespace=None):
|
||||||
"""Return an unused port from given namespace
|
"""Return an unused port from given namespace
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
import copy
|
import copy
|
||||||
import functools
|
import functools
|
||||||
|
import os.path
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
import netaddr
|
import netaddr
|
||||||
@ -776,12 +777,21 @@ class MetadataFakeProxyHandler(object):
|
|||||||
|
|
||||||
class MetadataL3AgentTestCase(L3AgentTestFramework):
|
class MetadataL3AgentTestCase(L3AgentTestFramework):
|
||||||
|
|
||||||
|
SOCKET_MODE = 0o644
|
||||||
|
|
||||||
def _create_metadata_fake_server(self, status):
|
def _create_metadata_fake_server(self, status):
|
||||||
server = utils.UnixDomainWSGIServer('metadata-fake-server')
|
server = utils.UnixDomainWSGIServer('metadata-fake-server')
|
||||||
self.addCleanup(server.stop)
|
self.addCleanup(server.stop)
|
||||||
|
|
||||||
|
# NOTE(cbrandily): TempDir fixture creates a folder with 0o700
|
||||||
|
# permissions but metadata_proxy_socket folder must be readable by all
|
||||||
|
# users
|
||||||
|
self.useFixture(
|
||||||
|
helpers.RecursivePermDirFixture(
|
||||||
|
os.path.dirname(self.agent.conf.metadata_proxy_socket), 0o555))
|
||||||
server.start(MetadataFakeProxyHandler(status),
|
server.start(MetadataFakeProxyHandler(status),
|
||||||
self.agent.conf.metadata_proxy_socket,
|
self.agent.conf.metadata_proxy_socket,
|
||||||
workers=0, backlog=4096)
|
workers=0, backlog=4096, mode=self.SOCKET_MODE)
|
||||||
|
|
||||||
def test_access_to_metadata_proxy(self):
|
def test_access_to_metadata_proxy(self):
|
||||||
"""Test access to the l3-agent metadata proxy.
|
"""Test access to the l3-agent metadata proxy.
|
||||||
@ -830,6 +840,39 @@ class MetadataL3AgentTestCase(L3AgentTestFramework):
|
|||||||
self.assertIn(str(webob.exc.HTTPOk.code), firstline.split())
|
self.assertIn(str(webob.exc.HTTPOk.code), firstline.split())
|
||||||
|
|
||||||
|
|
||||||
|
class UnprivilegedUserMetadataL3AgentTestCase(MetadataL3AgentTestCase):
|
||||||
|
"""Test metadata proxy with least privileged user.
|
||||||
|
|
||||||
|
The least privileged user has uid=65534 and is commonly named 'nobody' but
|
||||||
|
not always, that's why we use its uid.
|
||||||
|
"""
|
||||||
|
|
||||||
|
SOCKET_MODE = 0o664
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(UnprivilegedUserMetadataL3AgentTestCase, self).setUp()
|
||||||
|
self.agent.conf.set_override('metadata_proxy_user', '65534')
|
||||||
|
self.agent.conf.set_override('metadata_proxy_watch_log', False)
|
||||||
|
|
||||||
|
|
||||||
|
class UnprivilegedUserGroupMetadataL3AgentTestCase(MetadataL3AgentTestCase):
|
||||||
|
"""Test metadata proxy with least privileged user/group.
|
||||||
|
|
||||||
|
The least privileged user has uid=65534 and is commonly named 'nobody' but
|
||||||
|
not always, that's why we use its uid.
|
||||||
|
Its group has gid=65534 and is commonly named 'nobody' or 'nogroup', that's
|
||||||
|
why we use its gid.
|
||||||
|
"""
|
||||||
|
|
||||||
|
SOCKET_MODE = 0o666
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(UnprivilegedUserGroupMetadataL3AgentTestCase, self).setUp()
|
||||||
|
self.agent.conf.set_override('metadata_proxy_user', '65534')
|
||||||
|
self.agent.conf.set_override('metadata_proxy_group', '65534')
|
||||||
|
self.agent.conf.set_override('metadata_proxy_watch_log', False)
|
||||||
|
|
||||||
|
|
||||||
class TestDvrRouter(L3AgentTestFramework):
|
class TestDvrRouter(L3AgentTestFramework):
|
||||||
def test_dvr_router_lifecycle_without_ha_without_snat_with_fips(self):
|
def test_dvr_router_lifecycle_without_ha_without_snat_with_fips(self):
|
||||||
self._dvr_router_lifecycle(enable_ha=False, enable_snat=False)
|
self._dvr_router_lifecycle(enable_ha=False, enable_snat=False)
|
||||||
|
@ -215,6 +215,11 @@ class FakeUser(object):
|
|||||||
self.pw_name = name
|
self.pw_name = name
|
||||||
|
|
||||||
|
|
||||||
|
class FakeGroup(object):
|
||||||
|
def __init__(self, name):
|
||||||
|
self.gr_name = name
|
||||||
|
|
||||||
|
|
||||||
class TestBaseOSUtils(base.BaseTestCase):
|
class TestBaseOSUtils(base.BaseTestCase):
|
||||||
|
|
||||||
EUID = 123
|
EUID = 123
|
||||||
@ -264,6 +269,34 @@ class TestBaseOSUtils(base.BaseTestCase):
|
|||||||
geteuid.assert_called_once_with()
|
geteuid.assert_called_once_with()
|
||||||
getpwuid.assert_called_once_with(self.EUID)
|
getpwuid.assert_called_once_with(self.EUID)
|
||||||
|
|
||||||
|
@mock.patch('os.getegid', return_value=EGID)
|
||||||
|
@mock.patch('grp.getgrgid', return_value=FakeGroup(EGNAME))
|
||||||
|
def test_is_effective_group_id(self, getgrgid, getegid):
|
||||||
|
self.assertTrue(utils.is_effective_group(self.EGID))
|
||||||
|
getegid.assert_called_once_with()
|
||||||
|
self.assertFalse(getgrgid.called)
|
||||||
|
|
||||||
|
@mock.patch('os.getegid', return_value=EGID)
|
||||||
|
@mock.patch('grp.getgrgid', return_value=FakeGroup(EGNAME))
|
||||||
|
def test_is_effective_group_str_id(self, getgrgid, getegid):
|
||||||
|
self.assertTrue(utils.is_effective_group(str(self.EGID)))
|
||||||
|
getegid.assert_called_once_with()
|
||||||
|
self.assertFalse(getgrgid.called)
|
||||||
|
|
||||||
|
@mock.patch('os.getegid', return_value=EGID)
|
||||||
|
@mock.patch('grp.getgrgid', return_value=FakeGroup(EGNAME))
|
||||||
|
def test_is_effective_group_name(self, getgrgid, getegid):
|
||||||
|
self.assertTrue(utils.is_effective_group(self.EGNAME))
|
||||||
|
getegid.assert_called_once_with()
|
||||||
|
getgrgid.assert_called_once_with(self.EGID)
|
||||||
|
|
||||||
|
@mock.patch('os.getegid', return_value=EGID)
|
||||||
|
@mock.patch('grp.getgrgid', return_value=FakeGroup(EGNAME))
|
||||||
|
def test_is_not_effective_group(self, getgrgid, getegid):
|
||||||
|
self.assertFalse(utils.is_effective_group('wrong'))
|
||||||
|
getegid.assert_called_once_with()
|
||||||
|
getgrgid.assert_called_once_with(self.EGID)
|
||||||
|
|
||||||
|
|
||||||
class TestUnixDomainHttpConnection(base.BaseTestCase):
|
class TestUnixDomainHttpConnection(base.BaseTestCase):
|
||||||
def test_connect(self):
|
def test_connect(self):
|
||||||
|
@ -23,6 +23,7 @@ from neutron.agent.common import config as agent_config
|
|||||||
from neutron.agent.l3 import agent as l3_agent
|
from neutron.agent.l3 import agent as l3_agent
|
||||||
from neutron.agent.l3 import config as l3_config
|
from neutron.agent.l3 import config as l3_config
|
||||||
from neutron.agent.l3 import ha as l3_ha_agent
|
from neutron.agent.l3 import ha as l3_ha_agent
|
||||||
|
from neutron.agent.metadata import config
|
||||||
from neutron.agent.metadata import driver as metadata_driver
|
from neutron.agent.metadata import driver as metadata_driver
|
||||||
from neutron.openstack.common import uuidutils
|
from neutron.openstack.common import uuidutils
|
||||||
from neutron.tests import base
|
from neutron.tests import base
|
||||||
@ -77,7 +78,8 @@ class TestMetadataDriverProcess(base.BaseTestCase):
|
|||||||
|
|
||||||
cfg.CONF.register_opts(l3_config.OPTS)
|
cfg.CONF.register_opts(l3_config.OPTS)
|
||||||
cfg.CONF.register_opts(l3_ha_agent.OPTS)
|
cfg.CONF.register_opts(l3_ha_agent.OPTS)
|
||||||
cfg.CONF.register_opts(metadata_driver.MetadataDriver.OPTS)
|
cfg.CONF.register_opts(config.SHARED_OPTS)
|
||||||
|
cfg.CONF.register_opts(config.DRIVER_OPTS)
|
||||||
|
|
||||||
def _test_spawn_metadata_proxy(self, expected_user, expected_group,
|
def _test_spawn_metadata_proxy(self, expected_user, expected_group,
|
||||||
user='', group='', watch_log=True):
|
user='', group='', watch_log=True):
|
||||||
|
@ -20,6 +20,7 @@ import webob
|
|||||||
|
|
||||||
from neutron.agent.linux import utils as agent_utils
|
from neutron.agent.linux import utils as agent_utils
|
||||||
from neutron.agent.metadata import agent
|
from neutron.agent.metadata import agent
|
||||||
|
from neutron.agent.metadata import config
|
||||||
from neutron.agent import metadata_agent
|
from neutron.agent import metadata_agent
|
||||||
from neutron.common import constants
|
from neutron.common import constants
|
||||||
from neutron.common import utils
|
from neutron.common import utils
|
||||||
@ -521,6 +522,7 @@ class TestUnixDomainMetadataProxy(base.BaseTestCase):
|
|||||||
self.cfg.CONF.metadata_proxy_socket = '/the/path'
|
self.cfg.CONF.metadata_proxy_socket = '/the/path'
|
||||||
self.cfg.CONF.metadata_workers = 0
|
self.cfg.CONF.metadata_workers = 0
|
||||||
self.cfg.CONF.metadata_backlog = 128
|
self.cfg.CONF.metadata_backlog = 128
|
||||||
|
self.cfg.CONF.metadata_proxy_socket_mode = config.USER_MODE
|
||||||
|
|
||||||
@mock.patch.object(agent_utils, 'ensure_dir')
|
@mock.patch.object(agent_utils, 'ensure_dir')
|
||||||
def test_init_doesnot_exists(self, ensure_dir):
|
def test_init_doesnot_exists(self, ensure_dir):
|
||||||
@ -569,7 +571,7 @@ class TestUnixDomainMetadataProxy(base.BaseTestCase):
|
|||||||
mock.call('neutron-metadata-agent'),
|
mock.call('neutron-metadata-agent'),
|
||||||
mock.call().start(handler.return_value,
|
mock.call().start(handler.return_value,
|
||||||
'/the/path', workers=0,
|
'/the/path', workers=0,
|
||||||
backlog=128),
|
backlog=128, mode=0o644),
|
||||||
mock.call().wait()]
|
mock.call().wait()]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user