做OpenStack这套东西,最绕不开也最容易被新手绕晕的就是项目(Project)、用户(User)、角色(Role)这三者的关系。很多刚接触OpenStack的人,看完官方文档里那句“用户属于项目,角色定义了用户在项目中的权限”之后,依然一脸茫然——好像懂了,一上手配权限就乱套。这篇东西我就用实际干活的经验,把这层关系彻底掰开揉碎讲清楚,顺便把那些文档里不写、但你在生产环境一定会踩的坑也一并说了。
1. 三个概念的真实定义:别再拿“组”和“权限组”去套
先把这个最核心的认知误区掰过来。很多人习惯拿Windows或者传统Linux里的“用户组”概念去理解OpenStack的项目,结果做出来的权限模型一塌糊涂。Three者之间的本质区别,其实从OpenStack的源头设计里就能看明白。
1.1 项目(Project)不是用户组,是“资源隔离边界”
Project在OpenStack里最准确的理解是“资源的集合与隔离边界”。在Nova里叫“项目”或“租户”(Tenant),在Cinder、Neutron里也都以项目作为资源归属的基本单位。你创建的所有云主机、卷、网络、子网、安全组、镜像,以及Swift里的容器,都必须归属于且只能归属于某一个Project。
一个Project内部有独立的配额体系(Quota),比如能创建多少个实例、多少核CPU、多少GB内存、多少块卷。项目与项目之间默认是二层网络隔离的(通过VLAN、VXLAN等网络技术实现),资源不能跨项目互相可见。这就是“隔离边界”的物理含义。
举个例子:你在Project A里创建了一台云主机,它的网卡接在Project A的虚拟网络上。Project B里的云主机,哪怕和你在同一台物理计算节点上,也完全感知不到它的存在。从网络层面、存储层面、资源配额层面,Project之间都是独立的。
1.2 用户(User)就是“自然人”,与项目没有必然绑定关系
User这个概念的定位就简单得多,它就是一个个独立的登录身份,对应一个真实的人、一个服务账号、或者一个API调用的主体。一个User可以拥有全局层面的属性,比如用户名、密码、邮箱、是否启用等。
关键点在于:User本身不直接拥有任何OpenStack资源,它必须“进入”到某个Project里,才能真正干活。这就好比一个人(User)进了一个公司(Project)才能拿到工位、电脑和业务资源;但这个人本身可以是多个公司的员工——在OpenStack里,一个User可以同时属于多个Project,而且在每个Project里的权限可以完全不同。
我见过不少从传统IT运维转过来的人,喜欢把User当成“员工账号”、把Project当成“部门”,然后问“那我是不是该给每个部门建一个单独的用户组?”——不是的。OpenStack没有独立的“用户组”概念(虽然Keystone后来加入了Group,但那是为了批量授权,它的定位也变了,后面我会单独讲),权限的载体是“用户在某个项目里被赋予了什么角色”,不是“用户属于哪个组”。
1.3 角色(Role)是“授权令牌”,决定的是“能干什么”
Role是三者中最容易理解但也最容易配置出错的一个。它的定义非常直白:一个角色代表一组权限的集合。当把一个User关联到一个Project,再给这个关联关系赋予一个或多个Role时,这个User在这个Project内部就拥有了对应角色所定义的权限。
OpenStack默认提供了两个内置角色:admin和member(旧版本还有_member_,带下划线,版本迭代中逐渐被member替代)。但需要注意的是,这两个角色在不同服务里的含义是有差异的:
admin:在Keystone层面,admin角色可以管理用户、项目和角色本身(取决于policy.json的配置);在Nova里,admin角色的用户可以查看所有租户的云主机、执行迁移、关机等管理操作。member:这是一个比较标准的“业务操作员”角色,在Nova里可以创建、删除自己的云主机,在Neutron里可以管理自己的网络,在Swift里可以操作自己容器里的对象。
真正让你在配置时需要用到的角色,往往不只是这两个。比如Horizon里有个heat_stack_owner角色,FWAAS有个fwaas_admin,heat还有个heat_stack_user。如果创建一个用户并赋予它在某个项目里创建编排栈的权限,却忘了加heat_stack_owner,这个用户会在Horizon里点击“创建堆栈”时被干脆利落地拒绝。
1.4 为什么这个铁三角关系容易搞混
搞混的根源在于,OpenStack的授权模型并不是“用户–角色–项目”的三元组,而是**“用户–项目”的二元关联 + “角色”对这个关联的修饰**。官方文档管这个叫**“赋值”(Assignment)**——即“用户X在项目Y中被赋予了角色Z”。
这个设计是Keystone的重中之重。你不需要先定义“用户属于哪些项目”,也不需要先问“这个项目有哪些角色”,你需要先理解OpenStack的数据模型:一个User对应多个Assignment,一个Project也对应多个Assignment,每个Assignment绑定一个或一组Role。真正生效的权限是Assignment里Role的组合。
在这种模型下,“一个用户属于多个项目”就不再是一个需要特殊处理的例外情况,而是模型的原生能力。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 项目、用户、角色怎么串起来:一次完整的授权链路拆解
理论说完了,我从实际操作侧把这个模型如何运转到底层讲透。这样遇到权限问题你才能从数据流的角度去排查,而不是猜。
2.1 Keystone里的一条核心链路:Token → Project → Role
以OpenStack最常见的认证流程为例。用户使用openstack login或者直接用API发一个认证请求时,实际上是在做一次租户选择:
bash复制openstack --os-project-name myproject --os-username alice --os-password xxx token issue
这一步发生的事,是向Keystone请求一个Scoped Token(绑定到myproject这个项目的作用域令牌)。Keystone收到这个请求后,会在它的三张核心表(user表、project表、assignment表)里做一次联合查询:alice这个用户在myproject这个项目里有哪些角色?如果查询结果为空,比如这个用户压根不在这项目里,Keystone会直接返回一个HTTP 401 Unauthorized。
如果找到了角色,Keystone就把这些角色信息打包进Token里。之后这个用户拿着这个Token去请求Nova、Neutron、Cinder的API时,各服务会从Token里提取出项目ID和角色列表,然后基于各自的policy规则来决定放不放行。
