2. OpenShift项目与权限模型
在OpenShift上落地持续交付,第一件必须想清楚的事不是流水线用Jenkins还是Tekton,而是“把应用放在哪个Project里、让谁以什么身份去操作它”。OpenShift的权限模型以Kubernetes RBAC为基础,但增加了Project这一层面向开发者的抽象,以及SecurityContextConstraints(SCC)这一层容器安全约束。三者叠加,决定了流水线能否顺利构建、部署,以及是否在无意中放大了攻击面。
Project与Namespace:同一对象的两副面孔
Project本质上是带注解和额外元数据的Namespace。当你执行oc new-project cd-demo时,OpenShift会创建一个Namespace,并自动把当前用户绑定为该Project的admin。因此,Project是面向人的入口,Namespace是面向API的对象。在规划流水线时,建议按“环境+应用域”划分Project,而不是把所有环境塞进一个Project。例如:
cd-demo-dev # 开发环境,流水线频繁部署
cd-demo-test # 测试环境,用于集成验证
cd-demo-prod # 生产环境,仅允许受控发布
cd-demo-cicd # 流水线自身运行的项目(Tekton/Jenkins)
cd-demo-tools # 镜像仓库、SonarQube等共享工具
把CI/CD工具单独放在cd-demo-cicd,而不是与业务应用混在一起,有两个直接好处:一是流水线的ServiceAccount不会天然拥有业务Project的写权限;二是工具升级、资源配额和网络策略可以独立管理。跨Project部署时,再通过RoleBinding显式授权,权限边界清晰可审计。
ServiceAccount:流水线的“机器身份”
流水线中的每一步操作,最终都以某个ServiceAccount(SA)的身份调用API。默认情况下,每个Namespace都有一个default SA,但不应让流水线使用它。正确做法是为流水线创建专用SA,例如在cd-demo-cicd中创建pipeline-runner,在目标环境Project中创建deployer。SA的Token以Secret形式挂载,Tekton和Jenkins都可以通过serviceAccountName指定。
关键原则是:SA只拥有完成其职责所需的最小权限。构建阶段的SA需要读取源码、推送镜像;部署阶段的SA只需要在目标Project中创建和更新Deployment、Service、ConfigMap等资源,不应拥有删除Namespace或修改RBAC的权限。
Role、RoleBinding与ClusterRole:权限的授予方式
Role定义“能做什么”,RoleBinding定义“谁在哪个Project里拥有这个Role”。Role是Namespace级别的,ClusterRole是集群级别的。对于流水线,通常使用Role+RoleBinding即可,避免使用ClusterRoleBinding把权限扩散到全集群。
下面是一个部署SA的最小Role示例,只允许管理应用工作负载,不允许操作Secret和RBAC:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-deployer
namespace: cd-demo-dev
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["services", "configmaps"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: ["route.openshift.io"]
resources: ["routes"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
随后用RoleBinding把cd-demo-cicd中的pipeline-runner SA绑定到该Role。注意RoleBinding的subjects可以跨Namespace引用SA,这正是流水线跨Project部署的标准做法。
SecurityContextConstraints:容器能“多自由”
SCC是OpenShift特有的安全层,控制Pod能以什么用户运行、能否使用特权模式、能否挂载宿主机目录等。默认的restricted SCC要求容器以非root运行、禁止特权提升。流水线构建镜像时,如果使用Buildah或Kaniko,可能需要anyuid或自定义SCC;但部署到生产环境时,应坚持restricted。
常见误区是给流水线SA绑定privileged SCC“图省事”。这会让任何能修改流水线定义的人获得节点级权限。更安全的做法是:构建SA绑定一个仅允许必要能力的自定义SCC,部署SA保持restricted。SCC通过oc adm policy add-scc-to-user或add-scc-to-group绑定到SA。
为流水线规划项目结构的实操建议
结合上述模型,一个可落地的规划流程如下。第一步,创建五个Project:cd-demo-cicd、cd-demo-dev、cd-demo-test、cd-demo-prod、cd-demo-tools。第二步,在cd-demo-cicd中创建pipeline-runner SA,并为其绑定构建所需的Role和SCC。第三步,在三个环境Project中分别创建deployer SA,并绑定app-deployer Role。第四步,在cd-demo-cicd中创建RoleBinding,把pipeline-runner SA映射到各环境的deployer Role上。
验证权限是否最小化,可以用oc auth can-i命令模拟:
oc auth can-i create deployments \
--as=system:serviceaccount:cd-demo-cicd:pipeline-runner \
-n cd-demo-dev
# 期望输出:yes
oc auth can-i delete namespaces \
--as=system:serviceaccount:cd-demo-cicd:pipeline-runner \
-n cd-demo-dev
# 期望输出:no
如果第二条返回yes,说明权限过大,需要检查是否误绑了ClusterRole或过宽的Role。生产环境还应额外限制:禁止流水线SA读取Secret、禁止修改NetworkPolicy、禁止创建PodExec。这些都可以通过Role的resources和verbs精确控制。
常见陷阱与规避
第一个陷阱是“一个SA走天下”。构建、测试、部署共用一个SA,会导致权限只能取并集,无法最小化。第二个陷阱是“RoleBinding绑到Group而非SA”。绑到Group虽然方便,但人员变动时权限会意外扩散,流水线场景应优先绑SA。第三个陷阱是“忽略SCC”。很多部署失败并非RBAC问题,而是SCC拒绝了Pod的securityContext,例如镜像以root运行却被restricted SCC拦截。排查时可用oc describe pod查看事件中的SCC拒绝信息。
把Project、SA、Role、RoleBinding、SCC五者关系理清后,持续交付流水线就拥有了可审计、可收敛的权限底座。后续无论是接入Tekton、Argo CD还是Jenkins,都只是在这个底座上替换执行引擎,而权限模型本身保持稳定。