CI/CD 管道中最关键的 10 个安全风险以及如何降低这些风险。
OWASP 十大 CI/CD 安全风险确定了持续集成和持续交付管道中最重要的安全风险。CI/CD 管道是高价值目标,因为它们可以直接访问源代码、机密和生产环境。本指南涵盖流量控制、身份管理、依赖性攻击、管道中毒等内容。
流量控制机制的不足使得攻击者可以在没有适当审查或批准关卡的情况下通过 CI/CD 管道推送恶意代码。这包括绕过分支保护规则、缺少所需的审批,以及缺乏对谁可以触发部署到生产的强制规定。
如果没有适当的流程控制,单个受损的开发人员账户或恶意内部人员就可以绕过代码审查、安全扫描和审批流程,直接将代码推送到生产环境中。这可能导致部署后门、数据外泄代码或破坏性有效载荷。
# No branch protection — anyone can push directly to main name: Deploy on: push: branches: [main] # Triggers on any push to main jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: | # Deploys immediately — no approval gate! kubectl apply -f deploy.yaml kubectl rollout status deployment/myapp
name: Deploy on: push: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm test deploy: needs: test runs-on: ubuntu-latest environment: production # Requires manual approval steps: - uses: actions/checkout@v4 - run: | kubectl apply -f deploy.yaml kubectl rollout status deployment/myapp
CI/CD 系统涉及多个身份:人类用户、服务账户、机器人令牌和机器身份。不完善的 IAM 允许对资源库、管道和部署目标进行过度许可访问。共享凭证、过期账户和缺乏 MFA 会加剧风险。
权限过高的 CI/CD 身份被破坏后,可以修改管道、访问机密、更改构建工件并部署到生产中。共享服务账户无法审计谁执行了操作。
# Over-permissive workflow with admin token name: CI on: push permissions: write-all # Full permissions to everything! jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: | # Using org-wide PAT with admin access curl -H "Authorization: token ${{ secrets.ADMIN_PAT }}" \ https://api.github.com/repos/org/other-repo/contents/
name: CI on: push permissions: contents: read # Minimum required permissions packages: write # Only what's needed jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/create-github-app-token@v1 # Scoped app token id: app-token with: app-id: ${{ vars.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} repositories: other-repo # Scoped to specific repo
CI/CD 管道从外部软件包注册中心(npm、PyPI、Maven、Docker Hub)获取依赖关系。攻击者会通过依赖关系混乱、错别字抢注、维护者账户泄露和恶意软件包等方式利用这一点。一个中毒的依赖关系可在构建过程中执行任意代码。
恶意依赖在安装过程中执行代码(安装后脚本、setup.py)、窃取机密、向构建工件注入后门或建立持久性。SolarWinds 和 Codecov 等供应链攻击证明了其灾难性影响。
pipeline { agent any stages { stage('Build') { steps { // No lockfile verification, no integrity checks sh 'npm install' // Fetches latest — could be compromised! sh 'pip install -r requirements.txt' // No hash verification } } } }
pipeline { agent any stages { stage('Build') { steps { // Use lockfile with integrity verification sh 'npm ci' // Uses package-lock.json sh 'npm audit --audit-level=high' // Python: verify hashes from lockfile sh 'pip install --require-hashes -r requirements.lock' } } stage('SCA Scan') { steps { // Software Composition Analysis sh 'trivy fs --scanners vuln,secret .' } } } }
当攻击者可以修改 CI/CD 管道定义或注入在管道上下文中执行的恶意代码时,就会发生中毒管道执行(PPE)。这可能是通过操作分支中的管道配置文件、分叉中的拉取请求或修改共享管道模板发生的。
可以修改管道配置的攻击者可以访问管道可用的所有机密、凭证和权限。他们可以外泄机密、篡改构建输出或部署恶意代码--所有这一切都在受信任的执行环境中进行。
# Runs pipeline from fork PRs with access to secrets name: CI on: pull_request_target: # Runs in base repo context with secrets! branches: [main] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} # Checks out fork code! - run: make build # Fork's Makefile executes with secrets access env: DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
# Separate workflows: untrusted build + trusted deploy name: CI on: pull_request: # No secret access for PR builds branches: [main] permissions: contents: read jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # Checks out merge commit (safe) - run: npm ci && npm test # No secrets needed for build/test - uses: actions/upload-artifact@v4 with: name: build-output path: dist/
基于管道的访问控制(PBAC)管理管道可以访问的资源:云账户、Kubernetes 集群、数据库和内部服务。PBAC 不足意味着管道的访问权限超出需要,违反了最小特权原则。
权限过高的管道可被用来访问远远超出其预期范围的资源。一个次要服务的受损构建管道可被用于访问生产数据库、修改基础架构或转到其他环境。
# Pipeline with admin-level cloud credentials deploy: stage: deploy script: - aws configure set aws_access_key_id $AWS_ACCESS_KEY - aws configure set aws_secret_access_key $AWS_SECRET_KEY # This key has AdministratorAccess policy! - aws s3 sync dist/ s3://my-bucket/ - aws ecs update-service --cluster prod --service myapp # Same credentials could access ANY AWS resource
name: Deploy on: push: branches: [main] permissions: id-token: write # For OIDC contents: read jobs: deploy: runs-on: ubuntu-latest steps: - uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::123456:role/deploy-s3-only # Scoped role: only s3:PutObject on specific bucket aws-region: us-east-1 - run: aws s3 sync dist/ s3://my-bucket/
CI/CD 管道需要处理大量凭证:API 密钥、云令牌、注册表密码、SSH 密钥和签名证书。不良的凭据卫生状况包括在管道文件中硬编码秘密、在日志中打印秘密、使用未加密的秘密存储以及从不轮换凭据。
CI/CD 认证泄露是最常见的初始访问载体之一。在构建日志中暴露、提交到版本库或未加密存储的机密,可让攻击者直接访问生产系统、云账户和工件注册表。
#!/bin/bash # Secrets hardcoded and leaked in logs export DOCKER_PASSWORD="MyS3cret!" # Hardcoded! echo "Logging in with $DOCKER_PASSWORD" # Printed to logs! docker login -u admin -p "$DOCKER_PASSWORD" registry.example.com docker push registry.example.com/myapp:latest # AWS credentials in environment — visible in process listing export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCY" aws s3 cp artifact.zip s3://releases/
name: Publish on: push: tags: ['v*'] jobs: publish: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: docker/login-action@v3 # Handles credentials securely with: registry: registry.example.com username: ${{ secrets.DOCKER_USER }} # Masked in logs password: ${{ secrets.DOCKER_TOKEN }} # Short-lived token - run: | docker build -t registry.example.com/myapp:${{ github.ref_name }} . docker push registry.example.com/myapp:${{ github.ref_name }}
CI/CD 系统(Jenkins、GitLab、GitHub Actions runners)通常在不安全的默认配置下运行。这包括过时的软件版本、暴露的管理界面、禁用的安全功能、过于放任的网络访问以及跨项目共享的自托管运行程序。
配置错误的 CI/CD 基础架构可能会被利用来获取未经授权的构建环境访问权限、拦截机密或转入内部网络。共享的自托管运行程序允许跨项目攻击,其中一个受损的工作流程会影响到其他工作流程。
// Jenkins with insecure configuration // - Script console enabled without auth // - Agent-to-controller access unrestricted // - Outdated plugins with known CVEs pipeline { agent any // Runs on any available agent — no isolation stages { stage('Build') { steps { // Running as root on shared agent sh 'whoami' // root sh 'docker build -t myapp .' } } } }
pipeline { agent { kubernetes { // Ephemeral, isolated pod per build yaml """ apiVersion: v1 kind: Pod spec: securityContext: runAsNonRoot: true runAsUser: 1000 containers: - name: builder image: builder:1.2.3 securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true """ } } stages { stage('Build') { steps { container('builder') { sh 'make build' } } } } }
CI/CD 管道通常会集成第三方服务:代码质量工具、安全扫描仪、通知系统和部署平台。这些集成会被授予访问令牌和权限,从而创建一个信任链。不受监管的使用意味着无法了解第三方服务可以访问什么或做什么。
受到攻击的第三方服务(如 Codecov 漏洞)可以访问源代码、机密和构建工件。如果缺乏治理,团队可能会向未知服务授予过多权限,从而在供应链中形成隐形攻击载体。
name: CI on: push jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm test # Unknown third-party action with full repo access - uses: random-org/code-analysis@main # Unpinned, unvetted! with: token: ${{ secrets.GITHUB_TOKEN }} # Full token access! # Uploading coverage to external service with repo token - run: | bash <(curl -s https://example.com/uploader.sh) # Remote script!
name: CI on: push permissions: contents: read jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm test # Vetted action pinned to SHA - uses: github/codeql-action/analyze@8a470fddafa5cbc14 # Pinned SHA # Upload via official CLI tool, not remote scripts - uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 with: token: ${{ secrets.CODECOV_TOKEN }} # Scoped token fail_ci_if_error: true
构建工件(容器镜像、二进制文件、软件包)通过 CI/CD 管道流向生产。如果没有完整性验证,工件在任何时候都可能被篡改:在构建过程中、在传输过程中、在工件注册表中或在部署时。这会破坏从代码到生产的信任链。
被篡改的工件可能包含后门、恶意软件或修改过的逻辑。如果没有签名和验证,就无法检测工件是否在构建后被修改过。攻击者可以替换注册表中的合法图像,或在传输过程中拦截工件。
#!/bin/bash # Build and deploy without any integrity checks docker build -t myregistry.com/app:latest . docker push myregistry.com/app:latest # On deployment side — no verification docker pull myregistry.com/app:latest # Could be tampered! docker run myregistry.com/app:latest # Tag is mutable!
name: Build and Sign on: push: tags: ['v*'] permissions: id-token: write packages: write jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: | # Build with immutable tag (SHA) docker build -t myregistry.com/app:${{ github.sha }} . docker push myregistry.com/app:${{ github.sha }} - uses: sigstore/cosign-installer@v3 - run: | # Sign image with keyless signing (Sigstore) cosign sign myregistry.com/app:${{ github.sha }} # Generate and attach SBOM syft myregistry.com/app:${{ github.sha }} -o spdx-json > sbom.json cosign attest --predicate sbom.json myregistry.com/app:${{ github.sha }}
CI/CD 环境会产生关键的安全事件:管道执行、配置更改、秘密访问和部署活动。如果没有全面的日志记录和监控,管道中的恶意活动就不会被发现,事件响应也会受到严重影响。
由于缺乏对 CI/CD 活动的可视性,攻击者可以在不触发任何警报的情况下修改管道、窃取机密和篡改工件。由于缺乏审计跟踪,因此无法确定漏洞的范围和影响。
#!/bin/bash # Pipeline with no logging or audit trail echo "Starting deployment..." kubectl apply -f deploy.yaml echo "Done." # No record of: who triggered this, what changed, # which image was deployed, what secrets were accessed # Build logs expire after 30 days with no archival
name: Audited Deploy on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Log deployment metadata run: | echo "=== Deployment Audit Log ===" echo "Triggered by: ${{ github.actor }}" echo "Commit: ${{ github.sha }}" echo "Ref: ${{ github.ref }}" echo "Workflow: ${{ github.workflow }}" echo "Run ID: ${{ github.run_id }}" - name: Deploy with audit run: | kubectl apply -f deploy.yaml 2>&1 | tee deploy.log # Send audit event to SIEM curl -X POST "${{ secrets.SIEM_WEBHOOK }}" \ -d '{"event":"deploy","actor":"${{ github.actor }}","sha":"${{ github.sha }}"}'
| 身份证 | 脆弱性 | 严重性 | 关键缓解措施 |
|---|---|---|---|
| CICD-SEC-1 | 流量控制机制不足 | Critical | 分支保护、所需审批、环境门 |
| CICD-SEC-2 | 身份和访问管理不足 | Critical | 最小权限令牌、OIDC、MFA、凭证轮换 |
| CICD-SEC-3 | 依赖链滥用 | Critical | 锁定文件、散列验证、私人登记册、SCA |
| CICD-SEC-4 | 中毒管道执行(PPE) | Critical | 单独构建/部署、不可变管道定义、分叉控制 |
| CICD-SEC-5 | PBAC 不足 | High | OIDC 联合、范围化 IAM 角色、环境分离 |
| CICD-SEC-6 | 证书卫生不足 | Critical | 秘密管理、日志屏蔽、轮换、秘密扫描 |
| CICD-SEC-7 | 不安全的系统配置 | High | 短暂运行、非 root、插件更新、网络隔离 |
| CICD-SEC-8 | 不受监管地使用第三方服务 | High | 服务清单、SHA 引脚、无远程脚本 |
| CICD-SEC-9 | 人工制品完整性验证不当 | High | 共同签名、准入控制、SLSA 出处 |
| CICD-SEC-10 | 日志记录和可见性不足 | Medium | 审计日志、SIEM 集成、警报、日志保留 |