Skip to content

Commit d6b0961

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "TPM: add RequestContext checks to functional tests"
2 parents e2eefc2 + 0f82c29 commit d6b0961

2 files changed

Lines changed: 72 additions & 5 deletions

File tree

nova/tests/functional/integrated_helpers.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -600,11 +600,13 @@ def _rebuild_server(self, server, image_uuid, expected_state='ACTIVE'):
600600
self.notifier.wait_for_versioned_notifications('instance.rebuild.end')
601601
return self._wait_for_state_change(server, expected_state)
602602

603-
def _migrate_server(self, server, host=None):
603+
def _migrate_server(self, server, host=None,
604+
expected_state='VERIFY_RESIZE', api=None):
604605
"""Cold migrate a server."""
605606
body = {'host': host} if host else None
606-
self.api.post_server_action(server['id'], {'migrate': body})
607-
return self._wait_for_state_change(server, 'VERIFY_RESIZE')
607+
api = api or self.api
608+
api.post_server_action(server['id'], {'migrate': body})
609+
return self._wait_for_state_change(server, expected_state)
608610

609611
def _resize_server(self, server, flavor_id):
610612
self.api.post_server_action(

nova/tests/functional/libvirt/test_vtpm.py

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
from unittest import mock
1717

18+
from castellan.common import exception as castellan_exc
1819
from castellan.common.objects import passphrase
1920
from castellan.key_manager import key_manager
2021
import fixtures
@@ -28,6 +29,7 @@
2829
from nova import objects
2930
from nova.tests.functional.api import client
3031
from nova.tests.functional.libvirt import base
32+
from nova import utils
3133

3234
CONF = nova.conf.CONF
3335
LOG = logging.getLogger(__name__)
@@ -48,6 +50,9 @@ def __init__(self, configuration):
4850
#: A mapping of UUIDs to passphrases.
4951
self._passphrases = {}
5052

53+
#: A mapping of UUIDs to RequestContext objects.
54+
self._contexts = {}
55+
5156
def create_key(self, context, algorithm, length, **kwargs):
5257
"""Creates a symmetric key.
5358
@@ -78,6 +83,7 @@ def store(self, context, managed_object, **kwargs):
7883
uuid = uuidutils.generate_uuid()
7984
managed_object._id = uuid # set the id to simulate persistence
8085
self._passphrases[uuid] = managed_object
86+
self._contexts[uuid] = context
8187

8288
return uuid
8389

@@ -91,6 +97,12 @@ def get(self, context, managed_object_id):
9197
if context is None:
9298
raise exception.Forbidden()
9399

100+
if context.user_id != self._contexts[managed_object_id].user_id:
101+
raise castellan_exc.KeyManagerError(
102+
'Key manager error: Forbidden: Secret payload retrieval '
103+
'attempt not allowed - please review your user/project '
104+
'privileges')
105+
94106
if managed_object_id not in self._passphrases:
95107
raise KeyError('cannot retrieve non-existent secret')
96108

@@ -104,11 +116,18 @@ def delete(self, context, managed_object_id):
104116
if context is None:
105117
raise exception.Forbidden()
106118

119+
if context.user_id != self._contexts[managed_object_id].user_id:
120+
raise castellan_exc.KeyManagerError(
121+
'Key manager error: Forbidden: Secret payload retrieval '
122+
'attempt not allowed - please review your user/project '
123+
'privileges')
124+
107125
if managed_object_id not in self._passphrases:
108126
raise exception.KeyManagerError(
109127
reason="cannot delete non-existent secret")
110128

111129
del self._passphrases[managed_object_id]
130+
del self._contexts[managed_object_id]
112131

113132
def add_consumer(self, context, managed_object_id, consumer_data):
114133
raise NotImplementedError(
@@ -123,8 +142,11 @@ def remove_consumer(self, context, managed_object_id, consumer_data):
123142

124143
class VTPMServersTest(base.ServersTestBase):
125144

126-
# many move operations are admin-only
127-
ADMIN_API = True
145+
# NOTE: ADMIN_API is intentionally not set to True in order to catch key
146+
# manager service secret ownership issues.
147+
148+
# Reflect reality more for async API requests like migration
149+
CAST_AS_CALL = False
128150

129151
def setUp(self):
130152
# enable vTPM and use our own fake key service
@@ -372,6 +394,16 @@ def test_resize_server__vtpm_to_no_vtpm(self):
372394
self.assertInstanceHasNoSecret(server)
373395

374396
def test_migrate_server(self):
397+
"""Test cold migrate as a non-admin user.
398+
399+
Cold migrate policy defaults to admin-only but this will not currently
400+
work as admin due to key manager service secret ownership.
401+
"""
402+
# Allow non-admin to cold migrate a server.
403+
rules = {
404+
'os_compute_api:os-migrate-server:migrate': 'rule:admin_or_owner'}
405+
self.policy.set_rules(rules, overwrite=False)
406+
375407
for host in ('test_compute0', 'test_compute1'):
376408
self.start_compute(host)
377409

@@ -394,6 +426,39 @@ def test_migrate_server(self):
394426
# ensure nothing has changed
395427
self.assertInstanceHasSecret(server)
396428

429+
def test_migrate_server_as_admin(self):
430+
"""Test cold migrate as an admin user.
431+
432+
Cold migrate policy defaults to admin-only but this will not currently
433+
work as admin due to key manager service secret ownership.
434+
"""
435+
for host in ('test_compute0', 'test_compute1'):
436+
self.start_compute(host)
437+
438+
# create a server with vTPM
439+
server = self._create_server_with_vtpm()
440+
441+
# ensure our instance's system_metadata field is correct
442+
self.assertInstanceHasSecret(server)
443+
444+
with mock.patch(
445+
'nova.virt.libvirt.driver.LibvirtDriver'
446+
'.migrate_disk_and_power_off', return_value='{}',
447+
):
448+
# cold migrate the server
449+
self._migrate_server(
450+
server, expected_state='ERROR', api=self.admin_api)
451+
452+
# Migration should have failed due to permissions error.
453+
# Need microversion 2.84 to get events.details field.
454+
with utils.temporary_mutation(self.admin_api, microversion='2.84'):
455+
event = self._wait_for_instance_action_event(
456+
server, 'migrate', 'compute_finish_resize', 'Error')
457+
msg = ('Key manager error: Forbidden: Secret payload retrieval '
458+
'attempt not allowed - please review your user/project '
459+
'privileges')
460+
self.assertIn(msg, event['details'])
461+
397462
def test_live_migrate_server(self):
398463
for host in ('test_compute0', 'test_compute1'):
399464
self.start_compute(host)

0 commit comments

Comments
 (0)