GitLab CI流水线权限隔离
方案概述
本方案实现在GitLab CI/CD中根据不同人员的权限级别执行不同的流水线步骤,主要基于GitLab的以下特性:
rules
条件判断variables
变量传递only/except
条件限制- 用户权限API查询
基础权限模型设计
1. 用户角色定义
角色 | 描述 | 对应GitLab权限 |
---|---|---|
Developer | 普通开发人员 | Developer |
Maintainer | 项目维护者 | Maintainer |
Owner | 项目所有者 | Owner |
Auditor | 审计人员 | Reporter |
2. 权限与流水线阶段对应关系
流水线阶段 | Developer | Maintainer | Owner | Auditor |
---|---|---|---|---|
build | ✓ | ✓ | ✓ | ✓ |
test | ✓ | ✓ | ✓ | ✓ |
staging | ✗ | ✓ | ✓ | ✓ |
production | ✗ | ✗ | ✓ | ✗ |
audit | ✗ | ✗ | ✗ | ✓ |
实现方案
1. 基于分支保护的方案
stages:- build- test- staging- production- auditbuild:stage: buildscript: echo "Building..."rules:- if: '$CI_PIPELINE_SOURCE == "push"'test:stage: testscript: echo "Testing..."rules:- if: '$CI_PIPELINE_SOURCE == "push"'staging:stage: stagingscript: echo "Deploying to staging..."rules:- if: '$CI_COMMITTER_ACCESS_LEVEL >= 40' # Maintainer及以上- if: '$CI_DEPLOY_USER_ACCESS_LEVEL >= 40'production:stage: productionscript: echo "Deploying to production..."rules:- if: '$CI_COMMITTER_ACCESS_LEVEL == 50' # Only Owner- if: '$CI_DEPLOY_USER_ACCESS_LEVEL == 50'audit:stage: auditscript: echo "Running audit..."rules:- if: '$CI_COMMITTER_ACCESS_LEVEL == 20' # Reporter- if: '$CI_DEPLOY_USER_ACCESS_LEVEL == 20'
2. 基于自定义变量的方案(更灵活)
variables:# 通过API获取用户权限级别USER_ACCESS_LEVEL: $(curl --header "PRIVATE-TOKEN: $CI_JOB_TOKEN" \"$CI_API_V4_URL/projects/$CI_PROJECT_ID/members/$GITLAB_USER_ID" | \jq '.access_level')stages:- build- test- staging- production- audit.job_template: &job_settingsinterruptible: truetags:- dockerbuild:<<: *job_settingsstage: buildscript: echo "Building..."rules:- if: '$USER_ACCESS_LEVEL >= 30' # Developer+test:<<: *job_settingsstage: testscript: echo "Testing..."rules:- if: '$USER_ACCESS_LEVEL >= 30' # Developer+staging:<<: *job_settingsstage: stagingscript: echo "Deploying to staging..."rules:- if: '$USER_ACCESS_LEVEL >= 40' # Maintainer+production:<<: *job_settingsstage: productionscript: echo "Deploying to production..."rules:- if: '$USER_ACCESS_LEVEL == 50' # Owner only- when: manualaudit:<<: *job_settingsstage: auditscript: echo "Running audit..."rules:- if: '$USER_ACCESS_LEVEL == 20' # Reporter only
3. 基于分支+角色的混合方案
stages:- pre-build- build- test- deploypre-build:stage: pre-buildscript:- |# 根据用户权限设置变量if [ $CI_COMMITTER_ACCESS_LEVEL -ge 40 ]; thenecho "DEPLOY_ENV=staging" >> deploy.envfiif [ $CI_COMMITTER_ACCESS_LEVEL -eq 50 ]; thenecho "DEPLOY_ENV=production" >> deploy.envfiartifacts:reports:dotenv: deploy.envbuild:stage: buildscript: echo "Building..."rules:- if: '$CI_PIPELINE_SOURCE == "push"'test:stage: testscript: echo "Testing..."rules:- if: '$CI_PIPELINE_SOURCE == "push"'deploy-staging:stage: deployscript: echo "Deploying to staging..."rules:- if: '$DEPLOY_ENV == "staging"'needs: ["pre-build"]deploy-production:stage: deployscript: echo "Deploying to production..."rules:- if: '$DEPLOY_ENV == "production"'- when: manualneeds: ["pre-build"]
高级控制方案
1. 使用项目变量控制
-
在GitLab项目设置中创建变量:
PROD_DEPLOY_GROUPS
= “owner-group”STAGING_DEPLOY_GROUPS
= “maintainer-group,owner-group”
-
在.gitlab-ci.yml中:
deploy-prod:stage: deployscript: ./deploy-prod.shrules:- if: '$CI_COMMITTER_ACCESS_LEVEL == 50 || $CI_USER_GROUP =~ $PROD_DEPLOY_GROUPS'- when: manual
2. 使用外部权限服务
deploy:stage: deploybefore_script:- |ACCESS_LEVEL=$(curl -s "https://auth-service.example.com/check?user=$GITLAB_USER_LOGIN&project=$CI_PROJECT_ID")export DEPLOY_ACCESS=$ACCESS_LEVELscript:- |if [ "$DEPLOY_ACCESS" == "prod" ]; then./deploy-prod.shelif [ "$DEPLOY_ACCESS" == "stage" ]; then./deploy-stage.shelseecho "No deploy permission"exit 1firules:- if: '$CI_PIPELINE_SOURCE == "web" || $CI_PIPELINE_SOURCE == "api"'
最佳实践建议
-
权限验证双重检查:
- 前端通过.gitlab-ci.yml限制
- 后端在实际部署脚本中再次验证
-
审计日志:
after_script:- |echo "$(date): $GITLAB_USER_EMAIL ran $CI_JOB_NAME" >> /var/log/ci_audit.log
-
紧急覆盖机制:
deploy-emergency:stage: deployscript: ./deploy-prod.shrules:- if: '$CI_EMERGENCY_DEPLOY == "true" && $CI_COMMITTER_ACCESS_LEVEL >= 40'- when: never
-
权限矩阵可视化:
- 在项目README中维护权限矩阵表
- 使用CI Lint工具验证规则
注意事项
- 敏感操作(如生产部署)建议始终保留
when: manual
作为最后保障 CI_COMMITTER_ACCESS_LEVEL
在合并请求流水线中可能不可用,需使用CI_MERGE_REQUEST_SOURCE_BRANCH_SHA
- 对于fork的项目,需要特别处理权限检查
- 缓存和artifacts在不同权限的job之间共享时要注意安全
调试技巧
-
添加调试job查看权限信息:
show-info:stage: .prescript:- echo "User: $GITLAB_USER_LOGIN"- echo "Access level: $CI_COMMITTER_ACCESS_LEVEL"- echo "Groups: $CI_USER_GROUPS"rules:- when: always
-
使用CI Lint工具测试规则逻辑
-
查看流水线变量的实际值:
curl --header "PRIVATE-TOKEN: <your-token>" "https://gitlab.example.com/api/v4/projects/$CI_PROJECT_ID/pipelines/$CI_PIPELINE_ID/variables"