From 1d776bc16c033f33e61fd6832f2e94e24cdd1c5f Mon Sep 17 00:00:00 2001 From: Cedric Brandily Date: Mon, 10 Nov 2014 14:46:51 +0100 Subject: [PATCH] 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 --- etc/l3_agent.ini | 3 ++ neutron/agent/l3/config.py | 6 +++- neutron/agent/metadata/driver.py | 29 +++++++++++++++---- .../tests/unit/agent/metadata/test_driver.py | 16 ++++++++-- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/etc/l3_agent.ini b/etc/l3_agent.ini index 0c158370d..eca07f0f3 100644 --- a/etc/l3_agent.ini +++ b/etc/l3_agent.ini @@ -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 diff --git a/neutron/agent/l3/config.py b/neutron/agent/l3/config.py index d91bcdfe0..986317ff2 100644 --- a/neutron/agent/l3/config.py +++ b/neutron/agent/l3/config.py @@ -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')) ] diff --git a/neutron/agent/metadata/driver.py b/neutron/agent/metadata/driver.py index 5c778f39c..24a2fa9f3 100644 --- a/neutron/agent/metadata/driver.py +++ b/neutron/agent/metadata/driver.py @@ -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): diff --git a/neutron/tests/unit/agent/metadata/test_driver.py b/neutron/tests/unit/agent/metadata/test_driver.py index 48f87ea8d..0ce344d33 100644 --- a/neutron/tests/unit/agent/metadata/test_driver.py +++ b/neutron/tests/unit/agent/metadata/test_driver.py @@ -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=''): -- 2.45.2