Use rootwrap to execute iptables instead of requiring root
This patch set adds support for rootwrap in order to execute iptables. Co-Authored-By: Dmitry Tantsur <dtantsur@redhat.com> Change-Id: I7c424c17222f119730b8c5ac0daafd9906282e4d Closes-bug: #1495844
This commit is contained in:
parent
7e10d5c2fa
commit
52ef561c9f
24
README.rst
24
README.rst
@ -161,6 +161,23 @@ for the other possible configuration options.
|
||||
Configuration file contains a password and thus should be owned by ``root``
|
||||
and should have access rights like ``0600``.
|
||||
|
||||
**ironic-inspector** requires root rights for managing iptables. It gets them
|
||||
by running ``ironic-inspector-rootwrap`` utility with ``sudo``. To allow it,
|
||||
copy ``rootwrap.conf`` to the configuration directory (e.g. as
|
||||
``/etc/ironic-inspector/rootwrap.conf`` and create file
|
||||
``/etc/sudoers.d/ironic-inspector-rootwrap`` with the following content::
|
||||
|
||||
stack ALL=(root) NOPASSWD: /usr/bin/ironic-inspector-rootwrap /etc/ironic-inspector/rootwrap.conf *
|
||||
|
||||
.. note::
|
||||
``rootwrap.conf`` must be writeable only by root.
|
||||
|
||||
Replace ``stack`` with whatever user you'll be using to run
|
||||
**ironic-inspector**.
|
||||
|
||||
Configuring PXE
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
As for PXE boot environment, you'll need:
|
||||
|
||||
* TFTP server running and accessible (see below for using *dnsmasq*).
|
||||
@ -280,15 +297,10 @@ will be accessed by ramdisk on a booting machine).
|
||||
Running
|
||||
~~~~~~~
|
||||
|
||||
Run as ``root``::
|
||||
::
|
||||
|
||||
ironic-inspector --config-file /etc/ironic-inspector/inspector.conf
|
||||
|
||||
.. note::
|
||||
Running as ``root`` is not required if **ironic-inspector** does not
|
||||
manage the firewall (i.e. ``manage_firewall`` is set to ``false`` in the
|
||||
configuration file).
|
||||
|
||||
A good starting point for writing your own *systemd* unit should be `one used
|
||||
in Fedora <http://pkgs.fedoraproject.org/cgit/openstack-ironic-discoverd.git/plain/openstack-ironic-discoverd.service>`_
|
||||
(note usage of old name).
|
||||
|
@ -4,8 +4,9 @@ IRONIC_INSPECTOR_BIN_DIR=$(get_python_exec_prefix)
|
||||
IRONIC_INSPECTOR_BIN_FILE=$IRONIC_INSPECTOR_BIN_DIR/ironic-inspector
|
||||
IRONIC_INSPECTOR_CONF_DIR=${IRONIC_INSPECTOR_CONF_DIR:-/etc/ironic-inspector}
|
||||
IRONIC_INSPECTOR_CONF_FILE=$IRONIC_INSPECTOR_CONF_DIR/inspector.conf
|
||||
IRONIC_INSPECTOR_CMD="sudo $IRONIC_INSPECTOR_BIN_FILE --config-file $IRONIC_INSPECTOR_CONF_FILE"
|
||||
IRONIC_INSPECTOR_CMD="$IRONIC_INSPECTOR_BIN_FILE --config-file $IRONIC_INSPECTOR_CONF_FILE"
|
||||
IRONIC_INSPECTOR_DHCP_CONF_FILE=$IRONIC_INSPECTOR_CONF_DIR/dnsmasq.conf
|
||||
IRONIC_INSPECTOR_ROOTWRAP_CONF_FILE=$IRONIC_INSPECTOR_CONF_DIR/rootwrap.conf
|
||||
IRONIC_INSPECTOR_DATA_DIR=$DATA_DIR/ironic-inspector
|
||||
IRONIC_INSPECTOR_ADMIN_USER=${IRONIC_INSPECTOR_ADMIN_USER:-ironic-inspector}
|
||||
IRONIC_INSPECTOR_MANAGE_FIREWALL=$(trueorfalse True $IRONIC_INSPECTOR_MANAGE_FIREWALL)
|
||||
@ -145,6 +146,20 @@ function configure_inspector {
|
||||
if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ]; then
|
||||
setup_colorized_logging $IRONIC_INSPECTOR_CONF_FILE DEFAULT
|
||||
fi
|
||||
|
||||
cp "$IRONIC_INSPECTOR_DIR/rootwrap.conf" "$IRONIC_INSPECTOR_ROOTWRAP_CONF_FILE"
|
||||
cp -r "$IRONIC_INSPECTOR_DIR/rootwrap.d" "$IRONIC_INSPECTOR_CONF_DIR"
|
||||
local ironic_inspector_rootwrap=$(get_rootwrap_location ironic-inspector)
|
||||
local rootwrap_sudoer_cmd="$ironic_inspector_rootwrap $IRONIC_INSPECTOR_CONF_DIR/rootwrap.conf *"
|
||||
|
||||
# Set up the rootwrap sudoers for ironic-inspector
|
||||
local tempfile=`mktemp`
|
||||
echo "$STACK_USER ALL=(root) NOPASSWD: $rootwrap_sudoer_cmd" >$tempfile
|
||||
chmod 0640 $tempfile
|
||||
sudo chown root:root $tempfile
|
||||
sudo mv $tempfile /etc/sudoers.d/ironic-inspector-rootwrap
|
||||
|
||||
inspector_iniset DEFAULT rootwrap_config $IRONIC_INSPECTOR_ROOTWRAP_CONF_FILE
|
||||
}
|
||||
|
||||
function configure_inspector_swift {
|
||||
@ -188,6 +203,7 @@ function cleanup_inspector {
|
||||
rm -rf $IRONIC_INSPECTOR_DATA_DIR
|
||||
rm -f $IRONIC_TFTPBOOT_DIR/pxelinux.cfg/default
|
||||
rm -f $IRONIC_TFTPBOOT_DIR/ironic-inspector.*
|
||||
sudo rm -f /etc/sudoers.d/ironic-inspector-rootwrap
|
||||
|
||||
# Try to clean up firewall rules
|
||||
sudo iptables -D INPUT -i $IRONIC_INSPECTOR_INTERFACE -p udp \
|
||||
|
@ -63,6 +63,10 @@
|
||||
# value)
|
||||
#ipmi_address_fields = ilo_address,drac_host,cimc_address
|
||||
|
||||
# Path to the rootwrap configuration file to use for running commands
|
||||
# as root (string value)
|
||||
#rootwrap_config = /etc/ironic-inspector/rootwrap.conf
|
||||
|
||||
#
|
||||
# From oslo.log
|
||||
#
|
||||
@ -403,6 +407,9 @@
|
||||
# Verify HTTPS connections. (boolean value)
|
||||
#insecure = false
|
||||
|
||||
# The region in which the identity server can be found. (string value)
|
||||
#region_name = <None>
|
||||
|
||||
# Directory used to cache files related to PKI tokens. (string value)
|
||||
#signing_dir = <None>
|
||||
|
||||
|
@ -249,6 +249,10 @@ SERVICE_OPTS = [
|
||||
default=['ilo_address', 'drac_host', 'cimc_address'],
|
||||
help='Ironic driver_info fields that are equivalent '
|
||||
'to ipmi_address.'),
|
||||
cfg.StrOpt('rootwrap_config',
|
||||
default="/etc/ironic-inspector/rootwrap.conf",
|
||||
help='Path to the rootwrap configuration file to use for '
|
||||
'running commands as root'),
|
||||
]
|
||||
|
||||
|
||||
|
@ -29,7 +29,7 @@ NEW_CHAIN = None
|
||||
CHAIN = None
|
||||
INTERFACE = None
|
||||
LOCK = semaphore.BoundedSemaphore()
|
||||
BASE_COMMAND = ('iptables',)
|
||||
BASE_COMMAND = None
|
||||
|
||||
|
||||
def _iptables(*args, **kwargs):
|
||||
@ -61,19 +61,20 @@ def init():
|
||||
INTERFACE = CONF.firewall.dnsmasq_interface
|
||||
CHAIN = CONF.firewall.firewall_chain
|
||||
NEW_CHAIN = CHAIN + '_temp'
|
||||
BASE_COMMAND = ('sudo', 'ironic-inspector-rootwrap',
|
||||
CONF.rootwrap_config, 'iptables',)
|
||||
|
||||
# -w flag makes iptables wait for xtables lock, but it's not supported
|
||||
# everywhere yet
|
||||
try:
|
||||
with open(os.devnull, 'wb') as null:
|
||||
subprocess.check_call(['iptables', '-w', '-h'],
|
||||
subprocess.check_call(BASE_COMMAND + ('-w', '-h'),
|
||||
stderr=null, stdout=null)
|
||||
except subprocess.CalledProcessError:
|
||||
LOG.warn(_LW('iptables does not support -w flag, please update '
|
||||
'it to at least version 1.4.21'))
|
||||
BASE_COMMAND = ('iptables',)
|
||||
else:
|
||||
BASE_COMMAND = ('iptables', '-w')
|
||||
BASE_COMMAND += ('-w',)
|
||||
|
||||
_clean_up(CHAIN)
|
||||
# Not really needed, but helps to validate that we have access to iptables
|
||||
|
@ -39,6 +39,8 @@ class TestFirewall(test_base.NodeTest):
|
||||
self.assertEqual(0, mock_iptables.call_count)
|
||||
|
||||
def test_init_args(self, mock_call, mock_get_client, mock_iptables):
|
||||
rootwrap_path = '/some/fake/path'
|
||||
CONF.set_override('rootwrap_config', rootwrap_path)
|
||||
firewall.init()
|
||||
init_expected_args = [
|
||||
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport', '67',
|
||||
@ -52,10 +54,14 @@ class TestFirewall(test_base.NodeTest):
|
||||
for (args, call) in zip(init_expected_args, call_args_list):
|
||||
self.assertEqual(args, call[0])
|
||||
|
||||
self.assertEqual(('iptables', '-w'), firewall.BASE_COMMAND)
|
||||
expected = ('sudo', 'ironic-inspector-rootwrap', rootwrap_path,
|
||||
'iptables', '-w')
|
||||
self.assertEqual(expected, firewall.BASE_COMMAND)
|
||||
|
||||
def test_init_args_old_iptables(self, mock_call, mock_get_client,
|
||||
mock_iptables):
|
||||
rootwrap_path = '/some/fake/path'
|
||||
CONF.set_override('rootwrap_config', rootwrap_path)
|
||||
mock_call.side_effect = subprocess.CalledProcessError(2, '')
|
||||
firewall.init()
|
||||
init_expected_args = [
|
||||
@ -70,7 +76,9 @@ class TestFirewall(test_base.NodeTest):
|
||||
for (args, call) in zip(init_expected_args, call_args_list):
|
||||
self.assertEqual(args, call[0])
|
||||
|
||||
self.assertEqual(('iptables',), firewall.BASE_COMMAND)
|
||||
expected = ('sudo', 'ironic-inspector-rootwrap', rootwrap_path,
|
||||
'iptables',)
|
||||
self.assertEqual(expected, firewall.BASE_COMMAND)
|
||||
|
||||
def test_init_kwargs(self, mock_call, mock_get_client, mock_iptables):
|
||||
firewall.init()
|
||||
|
@ -16,6 +16,7 @@ oslo.config>=2.3.0 # Apache-2.0
|
||||
oslo.db>=2.4.1 # Apache-2.0
|
||||
oslo.i18n>=1.5.0 # Apache-2.0
|
||||
oslo.log>=1.8.0 # Apache-2.0
|
||||
oslo.rootwrap>=2.0.0 # Apache-2.0
|
||||
oslo.utils>=2.0.0 # Apache-2.0
|
||||
six>=1.9.0
|
||||
stevedore>=1.5.0 # Apache-2.0
|
||||
|
27
rootwrap.conf
Normal file
27
rootwrap.conf
Normal file
@ -0,0 +1,27 @@
|
||||
# Configuration for ironic-inspector-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/ironic-inspector/rootwrap.d,/usr/share/ironic-inspector/rootwrap
|
||||
|
||||
# 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, user0, user1...
|
||||
# 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
|
6
rootwrap.d/ironic-inspector-firewall.filters
Normal file
6
rootwrap.d/ironic-inspector-firewall.filters
Normal file
@ -0,0 +1,6 @@
|
||||
# ironic-inspector-rootwrap command filters for firewall manipulation
|
||||
# This file should be owned by (and only-writeable by) the root user
|
||||
|
||||
[Filters]
|
||||
# ironic_inspector/firewall.py
|
||||
iptables: CommandFilter, iptables, root
|
@ -21,6 +21,7 @@ packages =
|
||||
[entry_points]
|
||||
console_scripts =
|
||||
ironic-inspector = ironic_inspector.main:main
|
||||
ironic-inspector-rootwrap = oslo_rootwrap.cmd:main
|
||||
ironic_inspector.hooks.processing =
|
||||
scheduler = ironic_inspector.plugins.standard:SchedulerHook
|
||||
validate_interfaces = ironic_inspector.plugins.standard:ValidateInterfacesHook
|
||||
|
Loading…
Reference in New Issue
Block a user