Prevent spoofing instance_id from neutron to nova
Previously, one could update a port's device_id in neutron to be that of another tenant's instance_id and then be able to retrieve that instance's metadata. This patch prevents this from occurring by checking that X-Tenant-ID received from the metadata request matches the tenant_id in the nova database. DocImpact - This patch is dependent on another patch in neutron which adds X-Tenant-ID to the request. Therefore to minimize downtime one should upgrade Neutron first (then restart neutron-metadata-agent) and lastly update nova. Change-Id: I93bf662797c3986324ca2099b403833c2e990fb4 Closes-Bug: #1235450
This commit is contained in:
parent
4655df12b9
commit
07006be916
|
@ -144,6 +144,7 @@ class MetadataRequestHandler(wsgi.Application):
|
||||||
|
|
||||||
def _handle_instance_id_request(self, req):
|
def _handle_instance_id_request(self, req):
|
||||||
instance_id = req.headers.get('X-Instance-ID')
|
instance_id = req.headers.get('X-Instance-ID')
|
||||||
|
tenant_id = req.headers.get('X-Tenant-ID')
|
||||||
signature = req.headers.get('X-Instance-ID-Signature')
|
signature = req.headers.get('X-Instance-ID-Signature')
|
||||||
remote_address = req.headers.get('X-Forwarded-For')
|
remote_address = req.headers.get('X-Forwarded-For')
|
||||||
|
|
||||||
|
@ -151,8 +152,12 @@ class MetadataRequestHandler(wsgi.Application):
|
||||||
|
|
||||||
if instance_id is None:
|
if instance_id is None:
|
||||||
msg = _('X-Instance-ID header is missing from request.')
|
msg = _('X-Instance-ID header is missing from request.')
|
||||||
|
elif tenant_id is None:
|
||||||
|
msg = _('X-Tenant-ID header is missing from request.')
|
||||||
elif not isinstance(instance_id, basestring):
|
elif not isinstance(instance_id, basestring):
|
||||||
msg = _('Multiple X-Instance-ID headers found within request.')
|
msg = _('Multiple X-Instance-ID headers found within request.')
|
||||||
|
elif not isinstance(tenant_id, basestring):
|
||||||
|
msg = _('Multiple X-Tenant-ID headers found within request.')
|
||||||
else:
|
else:
|
||||||
msg = None
|
msg = None
|
||||||
|
|
||||||
|
@ -188,4 +193,12 @@ class MetadataRequestHandler(wsgi.Application):
|
||||||
LOG.error(_('Failed to get metadata for instance id: %s'),
|
LOG.error(_('Failed to get metadata for instance id: %s'),
|
||||||
instance_id)
|
instance_id)
|
||||||
|
|
||||||
|
if meta_data.instance['project_id'] != tenant_id:
|
||||||
|
LOG.warning(_("Tenant_id %(tenant_id)s does not match tenant_id "
|
||||||
|
"of instance %(instance_id)s."),
|
||||||
|
{'tenant_id': tenant_id,
|
||||||
|
'instance_id': instance_id})
|
||||||
|
# causes a 404 to be raised
|
||||||
|
meta_data = None
|
||||||
|
|
||||||
return meta_data
|
return meta_data
|
||||||
|
|
|
@ -510,6 +510,7 @@ class MetadataHandlerTestCase(test.TestCase):
|
||||||
relpath="/2009-04-04/user-data",
|
relpath="/2009-04-04/user-data",
|
||||||
address="192.192.192.2",
|
address="192.192.192.2",
|
||||||
headers={'X-Instance-ID': 'a-b-c-d',
|
headers={'X-Instance-ID': 'a-b-c-d',
|
||||||
|
'X-Tenant-ID': 'test',
|
||||||
'X-Instance-ID-Signature': signed})
|
'X-Instance-ID-Signature': signed})
|
||||||
self.assertEqual(response.status_int, 200)
|
self.assertEqual(response.status_int, 200)
|
||||||
|
|
||||||
|
@ -522,6 +523,7 @@ class MetadataHandlerTestCase(test.TestCase):
|
||||||
fake_get_metadata_by_instance_id=fake_get_metadata,
|
fake_get_metadata_by_instance_id=fake_get_metadata,
|
||||||
headers={'X-Forwarded-For': '192.192.192.2',
|
headers={'X-Forwarded-For': '192.192.192.2',
|
||||||
'X-Instance-ID': 'a-b-c-d',
|
'X-Instance-ID': 'a-b-c-d',
|
||||||
|
'X-Tenant-ID': 'test',
|
||||||
'X-Instance-ID-Signature': signed})
|
'X-Instance-ID-Signature': signed})
|
||||||
|
|
||||||
self.assertEqual(response.status_int, 200)
|
self.assertEqual(response.status_int, 200)
|
||||||
|
@ -536,10 +538,36 @@ class MetadataHandlerTestCase(test.TestCase):
|
||||||
fake_get_metadata_by_instance_id=fake_get_metadata,
|
fake_get_metadata_by_instance_id=fake_get_metadata,
|
||||||
headers={'X-Forwarded-For': '192.192.192.2',
|
headers={'X-Forwarded-For': '192.192.192.2',
|
||||||
'X-Instance-ID': 'a-b-c-d',
|
'X-Instance-ID': 'a-b-c-d',
|
||||||
|
'X-Tenant-ID': 'test',
|
||||||
'X-Instance-ID-Signature': ''})
|
'X-Instance-ID-Signature': ''})
|
||||||
|
|
||||||
self.assertEqual(response.status_int, 403)
|
self.assertEqual(response.status_int, 403)
|
||||||
|
|
||||||
|
# missing X-Tenant-ID from request
|
||||||
|
response = fake_request(
|
||||||
|
self.stubs, self.mdinst,
|
||||||
|
relpath="/2009-04-04/user-data",
|
||||||
|
address="192.192.192.2",
|
||||||
|
fake_get_metadata_by_instance_id=fake_get_metadata,
|
||||||
|
headers={'X-Forwarded-For': '192.192.192.2',
|
||||||
|
'X-Instance-ID': 'a-b-c-d',
|
||||||
|
'X-Instance-ID-Signature': signed})
|
||||||
|
|
||||||
|
self.assertEqual(response.status_int, 400)
|
||||||
|
|
||||||
|
# mismatched X-Tenant-ID
|
||||||
|
response = fake_request(
|
||||||
|
self.stubs, self.mdinst,
|
||||||
|
relpath="/2009-04-04/user-data",
|
||||||
|
address="192.192.192.2",
|
||||||
|
fake_get_metadata_by_instance_id=fake_get_metadata,
|
||||||
|
headers={'X-Forwarded-For': '192.192.192.2',
|
||||||
|
'X-Instance-ID': 'a-b-c-d',
|
||||||
|
'X-Tenant-ID': 'FAKE',
|
||||||
|
'X-Instance-ID-Signature': signed})
|
||||||
|
|
||||||
|
self.assertEqual(response.status_int, 404)
|
||||||
|
|
||||||
# without X-Forwarded-For
|
# without X-Forwarded-For
|
||||||
response = fake_request(
|
response = fake_request(
|
||||||
self.stubs, self.mdinst,
|
self.stubs, self.mdinst,
|
||||||
|
@ -547,6 +575,7 @@ class MetadataHandlerTestCase(test.TestCase):
|
||||||
address="192.192.192.2",
|
address="192.192.192.2",
|
||||||
fake_get_metadata_by_instance_id=fake_get_metadata,
|
fake_get_metadata_by_instance_id=fake_get_metadata,
|
||||||
headers={'X-Instance-ID': 'a-b-c-d',
|
headers={'X-Instance-ID': 'a-b-c-d',
|
||||||
|
'X-Tenant-ID': 'test',
|
||||||
'X-Instance-ID-Signature': signed})
|
'X-Instance-ID-Signature': signed})
|
||||||
|
|
||||||
self.assertEqual(response.status_int, 500)
|
self.assertEqual(response.status_int, 500)
|
||||||
|
@ -564,6 +593,7 @@ class MetadataHandlerTestCase(test.TestCase):
|
||||||
fake_get_metadata_by_instance_id=fake_get_metadata,
|
fake_get_metadata_by_instance_id=fake_get_metadata,
|
||||||
headers={'X-Forwarded-For': '192.192.192.2',
|
headers={'X-Forwarded-For': '192.192.192.2',
|
||||||
'X-Instance-ID': 'z-z-z-z',
|
'X-Instance-ID': 'z-z-z-z',
|
||||||
|
'X-Tenant-ID': 'test',
|
||||||
'X-Instance-ID-Signature': signed})
|
'X-Instance-ID-Signature': signed})
|
||||||
self.assertEqual(response.status_int, 500)
|
self.assertEqual(response.status_int, 500)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue