Allow to request metadata proxy only with redirection

metadata service should be requested on 169.254.169.254:80 and router
namespace iptables rules redirect the request to the metadata-ns-proxy
on 127.0.0.1:$metadata_port. But currently the metadata-ns-proxy can be
requested directly on $router-ip:$metadata_port.

To avoid such behavior, this change marks packets redirection in mangle
table (PREROUTING), redirects (PREROUTING) them in nat table, accepts
them in filter table (INPUT) using the mark. Packets send to the
metadata proxy port without mark (so directly) are dropped. The
mark can be configured through the new option metadata_access_mark.

Remark: redirected packets are not local packets (in general), so
setting metadata proxy server host to 127.0.0.1 will disallow direct
queries but so redirected queries.

DocImpact
Partial-Bug: #1187102
Change-Id: I6a9bb12c8bf68c6fcf4e4060f8dfe44a309a41da
This commit is contained in:
Cedric Brandily 2014-11-10 14:46:51 +01:00
parent 4143763913
commit 1d776bc16c
4 changed files with 45 additions and 9 deletions

View File

@ -71,6 +71,9 @@
# if the Nova metadata server is not available
# enable_metadata_proxy = True
# Iptables mangle mark used to mark metadata valid requests
# metadata_access_mark = 0x1
# Location of Metadata Proxy UNIX domain socket
# metadata_proxy_socket = $state_path/metadata_proxy

View File

@ -55,5 +55,9 @@ OPTS = [
cfg.BoolOpt('enable_metadata_proxy', default=True,
help=_("Allow running metadata proxy.")),
cfg.BoolOpt('router_delete_namespaces', default=False,
help=_("Delete namespace after removing a router."))
help=_("Delete namespace after removing a router.")),
cfg.StrOpt('metadata_access_mark',
default='0x1',
help=_('Iptables mangle mark used to mark metadata valid '
'requests'))
]

View File

@ -24,6 +24,9 @@ from neutron.services import advanced_service
LOG = logging.getLogger(__name__)
# Access with redirection to metadata proxy iptables mark mask
METADATA_ACCESS_MARK_MASK = '0xffffffff'
class MetadataDriver(advanced_service.AdvancedService):
@ -47,10 +50,14 @@ class MetadataDriver(advanced_service.AdvancedService):
def __init__(self, l3_agent):
super(MetadataDriver, self).__init__(l3_agent)
self.metadata_port = l3_agent.conf.metadata_port
self.metadata_access_mark = l3_agent.conf.metadata_access_mark
def after_router_added(self, router):
for c, r in self.metadata_filter_rules(self.metadata_port):
for c, r in self.metadata_filter_rules(self.metadata_port,
self.metadata_access_mark):
router.iptables_manager.ipv4['filter'].add_rule(c, r)
for c, r in self.metadata_mangle_rules(self.metadata_access_mark):
router.iptables_manager.ipv4['mangle'].add_rule(c, r)
for c, r in self.metadata_nat_rules(self.metadata_port):
router.iptables_manager.ipv4['nat'].add_rule(c, r)
router.iptables_manager.apply()
@ -61,8 +68,11 @@ class MetadataDriver(advanced_service.AdvancedService):
self.l3_agent.conf)
def before_router_removed(self, router):
for c, r in self.metadata_filter_rules(self.metadata_port):
for c, r in self.metadata_filter_rules(self.metadata_port,
self.metadata_access_mark):
router.iptables_manager.ipv4['filter'].remove_rule(c, r)
for c, r in self.metadata_mangle_rules(self.metadata_access_mark):
router.iptables_manager.ipv4['mangle'].remove_rule(c, r)
for c, r in self.metadata_nat_rules(self.metadata_port):
router.iptables_manager.ipv4['nat'].remove_rule(c, r)
router.iptables_manager.apply()
@ -72,9 +82,18 @@ class MetadataDriver(advanced_service.AdvancedService):
self.l3_agent.conf)
@classmethod
def metadata_filter_rules(cls, port):
return [('INPUT', '-s 0.0.0.0/0 -p tcp -m tcp --dport %s '
'-j ACCEPT' % port)]
def metadata_filter_rules(cls, port, mark):
return [('INPUT', '-m mark --mark %s -j ACCEPT' % mark),
('INPUT', '-s 0.0.0.0/0 -p tcp -m tcp --dport %s '
'-j DROP' % port)]
@classmethod
def metadata_mangle_rules(cls, mark):
return [('PREROUTING', '-s 0.0.0.0/0 -d 169.254.169.254/32 '
'-p tcp -m tcp --dport 80 '
'-j MARK --set-xmark %(value)s/%(mask)s' %
{'value': mark,
'mask': METADATA_ACCESS_MARK_MASK})]
@classmethod
def metadata_nat_rules(cls, port):

View File

@ -48,10 +48,20 @@ class TestMetadataDriver(base.BaseTestCase):
metadata_driver.MetadataDriver.metadata_nat_rules(8775))
def test_metadata_filter_rules(self):
rules = ('INPUT', '-s 0.0.0.0/0 -p tcp -m tcp --dport 8775 -j ACCEPT')
rules = [('INPUT', '-m mark --mark 0x1 -j ACCEPT'),
('INPUT', '-s 0.0.0.0/0 -p tcp -m tcp --dport 8775 -j DROP')]
self.assertEqual(
[rules],
metadata_driver.MetadataDriver.metadata_filter_rules(8775))
rules,
metadata_driver.MetadataDriver.metadata_filter_rules(8775, '0x1'))
def test_metadata_mangle_rules(self):
rule = ('PREROUTING', '-s 0.0.0.0/0 -d 169.254.169.254/32 '
'-p tcp -m tcp --dport 80 '
'-j MARK --set-xmark 0x1/%s' %
metadata_driver.METADATA_ACCESS_MARK_MASK)
self.assertEqual(
[rule],
metadata_driver.MetadataDriver.metadata_mangle_rules('0x1'))
def _test_spawn_metadata_proxy(self, expected_user, expected_group,
user='', group=''):