查看heat的stack创建流程,在create_stack接口中,可以看到如下一段代码:
def _create_stack_user(stack):
if not stack.stack_user_project_id:
try:
stack.create_stack_user_project_id()
except exception.AuthorizationFailure as ex:
stack.state_set(stack.action, stack.FAILED,
six.text_type(ex))
进一步查看create_stack_user_project_id的实现,其实就是调用了keystone client的相关接口。
(具体可以参考heat_keystoneclient.py的create_stack_domain_project接口实现)
而该接口会在keystone服务上新建一个project。
而在删除stack时,又会通过Stack的_delete_credentials把这个project删除。
那么这个临时创建的project是用来干什么的呢?
查看nova的server资源的代码实现,如果USER_DATA_FORMAT类型是SOFTWARE_CONFIG,
会调用_populate_deployments_metadata对metadata进行一些处理。
而_populate_deployments_metadata中有如下段落:
if self.transport_poll_server_heat(props):
occ.update({'heat': {
'user_id': self._get_user_id(),
'password': self.password,
'auth_url': self.context.auth_url,
'project_id': self.stack.stack_user_project_id,
'stack_id': self.stack.identifier().stack_path(),
'resource_name': self.name}})
elif self.transport_zaqar_message(props):
queue_id = self.physical_resource_name()
self.data_set('metadata_queue_id', queue_id)
zaqar_plugin = self.client_plugin('zaqar')
zaqar = zaqar_plugin.create_for_tenant(
self.stack.stack_user_project_id, self._user_token())
queue = zaqar.queue(queue_id)
occ.update({'zaqar': {
'user_id': self._get_user_id(),
'password': self.password,
'auth_url': self.context.auth_url,
'project_id': self.stack.stack_user_project_id,
'queue_id': queue_id}})
可以看到,如果software_config数据是通过heat或zaqar服务向VM提供,
那么stack_user_project_id就会作为参数传递给VM。
而VM在访问heat或zaqar服务的时候,就会用到这个project参数。
之所以会新建一个独立的project,而不是直接用发起创建stack操作的project,
应该是从权限控制角度考虑。通过新的project只能访问相关software_config资源。
试想如果把创建stack的project作为参数发送给了VM,VM其实就拥有了对该project关联资源的操作权限,
这是不安全的。