Add radvd_user config option
In some deployments, the "neutron" user does not have the permissions
to modify the kernel interfaces. In those cases the radvd user should
be defined. This patch introduces a new config option: "radvd_user".
This config option is the username passed to radvd, used to drop root
privileges and change user ID to username and group ID to the primary
group of username. If no user specified (by default is an empty string),
the user executing the L3 agent will be passed. If "root" specified,
because radvd is spawned as root, no "username" parameter will be
passed.
Change-Id: Ie9a6fbf04d453a3c1c0bddf9ecaa3d4d6467e8ff
Closes-Bug: #1844688
(cherry picked from commit 6a5a75d5a6
)
This commit is contained in:
parent
cb6f7ce08e
commit
6ec7ba8695
@ -150,8 +150,12 @@ class DaemonMonitor(object):
|
||||
|
||||
def _spawn_radvd(self, radvd_conf):
|
||||
def callback(pid_file):
|
||||
# drop radvd daemon privileges and run as the neutron user
|
||||
radvd_user = pwd.getpwuid(os.geteuid()).pw_name
|
||||
if not self._agent_conf.radvd_user:
|
||||
radvd_user = pwd.getpwuid(os.geteuid()).pw_name
|
||||
elif self._agent_conf.radvd_user == 'root':
|
||||
radvd_user = None
|
||||
else:
|
||||
radvd_user = self._agent_conf.radvd_user
|
||||
# we need to use -m syslog and f.e. not -m stderr (the default)
|
||||
# or -m stderr_syslog so that radvd 2.0+ will close stderr and
|
||||
# exit after daemonization; otherwise, the current thread will
|
||||
@ -160,8 +164,9 @@ class DaemonMonitor(object):
|
||||
radvd_cmd = [RADVD_SERVICE_CMD,
|
||||
'-C', '%s' % radvd_conf,
|
||||
'-p', '%s' % pid_file,
|
||||
'-u', '%s' % radvd_user,
|
||||
'-m', 'syslog']
|
||||
if radvd_user:
|
||||
radvd_cmd += ['-u', '%s' % radvd_user]
|
||||
return radvd_cmd
|
||||
|
||||
pm = self._get_radvd_process_manager(callback)
|
||||
|
@ -92,6 +92,14 @@ OPTS = [
|
||||
help=_('Iptables mangle mark used to mark ingress from '
|
||||
'external network. This mark will be masked with '
|
||||
'0xffff so that only the lower 16 bits will be used.')),
|
||||
cfg.StrOpt('radvd_user',
|
||||
default='',
|
||||
help=_('The username passed to radvd, used to drop root '
|
||||
'privileges and change user ID to username and group ID '
|
||||
'to the primary group of username. If no user specified '
|
||||
'(by default), the user executing the L3 agent will be '
|
||||
'passed. If "root" specified, because radvd is spawned '
|
||||
'as root, no "username" parameter will be passed.')),
|
||||
]
|
||||
|
||||
|
||||
|
@ -17,6 +17,8 @@ import copy
|
||||
import functools
|
||||
from itertools import chain as iter_chain
|
||||
from itertools import combinations as iter_combinations
|
||||
import os
|
||||
import pwd
|
||||
|
||||
import eventlet
|
||||
import fixtures
|
||||
@ -3086,9 +3088,9 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
||||
|
||||
self.assertFalse(ri.remove_floating_ip.called)
|
||||
|
||||
@mock.patch('os.geteuid', return_value='490')
|
||||
@mock.patch('pwd.getpwuid', return_value=FakeUser('neutron'))
|
||||
def test_spawn_radvd(self, geteuid, getpwuid):
|
||||
@mock.patch.object(os, 'geteuid', return_value=mock.ANY)
|
||||
@mock.patch.object(pwd, 'getpwuid')
|
||||
def test_spawn_radvd(self, mock_getpwuid, *args):
|
||||
router = l3_test_common.prepare_router_data(
|
||||
ip_version=lib_constants.IP_VERSION_6)
|
||||
|
||||
@ -3116,19 +3118,25 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
||||
agent.process_monitor,
|
||||
l3_test_common.FakeDev,
|
||||
self.conf)
|
||||
radvd.enable(router['_interfaces'])
|
||||
|
||||
cmd = execute.call_args[0][0]
|
||||
|
||||
self.assertIn('radvd', cmd)
|
||||
|
||||
_join = lambda *args: ' '.join(args)
|
||||
|
||||
cmd = _join(*cmd)
|
||||
self.assertIn(_join('-C', conffile), cmd)
|
||||
self.assertIn(_join('-p', pidfile), cmd)
|
||||
self.assertIn(_join('-u', 'neutron'), cmd)
|
||||
self.assertIn(_join('-m', 'syslog'), cmd)
|
||||
test_users = [('', 'stack', '-u stack'),
|
||||
('neutron', mock.ANY, '-u neutron'),
|
||||
('root', mock.ANY, None)]
|
||||
for radvd_user, os_user, to_check in test_users:
|
||||
self.conf.set_override('radvd_user', radvd_user)
|
||||
mock_getpwuid.return_value = FakeUser(os_user)
|
||||
radvd.enable(router['_interfaces'])
|
||||
cmd = execute.call_args[0][0]
|
||||
_join = lambda *args: ' '.join(args)
|
||||
cmd = _join(*cmd)
|
||||
self.assertIn('radvd', cmd)
|
||||
self.assertIn(_join('-C', conffile), cmd)
|
||||
self.assertIn(_join('-p', pidfile), cmd)
|
||||
self.assertIn(_join('-m', 'syslog'), cmd)
|
||||
if to_check:
|
||||
self.assertIn(to_check, cmd)
|
||||
else:
|
||||
self.assertNotIn('-u', cmd)
|
||||
|
||||
def test_generate_radvd_mtu_conf(self):
|
||||
router = l3_test_common.prepare_router_data()
|
||||
|
@ -0,0 +1,11 @@
|
||||
---
|
||||
other:
|
||||
- |
|
||||
A new config option, ``radvd_user``, was added to l3_agent.ini for the L3
|
||||
agent. This option defines the username passed to radvd, used to drop
|
||||
"root" privileges and change user ID to username and group ID to the
|
||||
primary group of the user. If no user specified (by default), the user
|
||||
executing the L3 agent will be passed. If "root" specified, because radvd
|
||||
is spawned as root, no "username" parameter will be passed.
|
||||
(For more information see bug `1844688
|
||||
<https://bugs.launchpad.net/neutron/+bug/1844688>`_.)
|
Loading…
Reference in New Issue
Block a user