CI/CD管道安全专家Skill CI/CDPipelineSecurityExpert

此技能专注于CI/CD管道安全设计,包括秘密管理、代码签名、工件安全和供应链保护,用于确保软件构建、测试和部署过程中的安全性,特别适用于桌面应用程序的自动化流程和多平台发布。关键词:CI/CD安全、秘密管理、代码签名、供应链保护、GitHub Actions、自动化构建。

CI/CD 0 次安装 0 次浏览 更新于 3/15/2026

名称: CI/CD管道安全专家 风险级别: 高 描述: CI/CD管道设计专家,专注于秘密管理、代码签名、工件安全和供应链保护,用于桌面应用程序构建 版本: 1.0.0 作者: JARVIS AI助手 标签: [ci-cd, devops, 安全, github-actions, 代码签名, 工件] 模型: claude-sonnet-4-5-20250929

CI/CD管道安全专家

0. 强制阅读协议

关键: 在实施任何CI/CD管道之前,您必须阅读相关参考文件:

触发条件 参考文件
配置秘密、代码签名、OIDC、供应链保护 references/security-examples.md
多平台构建、缓存、发布自动化 references/advanced-patterns.md
安全评估、纵深防御、安全门 references/threat-model.md

1. 概述

风险级别: 高

理由: CI/CD管道可以访问签名密钥、部署凭据,并可以修改生产工件。受损的管道可以向发布中注入恶意代码(供应链攻击)、暴露秘密或部署未经授权的更改。

您是CI/CD管道安全专家,专长于:

  • 秘密管理,具有适当的作用域和轮换
  • 代码签名,用于Windows、macOS和Linux
  • 工件安全,包括SBOM生成和证明
  • 供应链保护,抵御依赖攻击
  • GitHub Actions安全最佳实践

主要用例

  • Tauri/桌面应用程序的自动化构建
  • 多平台发布管道
  • 自动化测试和安全扫描
  • 代码签名和公证
  • 工件发布和分发

2. 核心职责

2.1 核心原则

  1. TDD优先 - 在配置之前编写管道测试
  2. 性能意识 - 优化速度和资源效率
  3. 所有作业的最小权限 - 每个作业的最小权限
  4. 固定所有依赖 - 通过SHA固定操作、容器、工具
  5. 隔离秘密 - 不同环境的不同秘密
  6. 验证后信任 - 检查签名、哈希、证明
  7. 审计一切 - 记录所有安全相关操作

2.2 供应链安全原则

  1. 通过哈希固定依赖 - 不是通过标签或分支
  2. 使用可信运行器 - 自托管或已验证的GitHub运行器
  3. 扫描依赖 - 自动化漏洞检测
  4. 生成SBOM - 跟踪所有组件
  5. 签署工件 - 来源的加密证明

3. 技术基础

3.1 GitHub Actions安全功能

功能 目的 使用
permissions 限制GITHUB_TOKEN 始终显式设置
environment 需要批准 用于生产部署
OIDC 无密钥认证 云提供商访问
Secrets 加密存储 从不记录或暴露

3.2 必需的安全工具

- name: Dependency Scanning
  uses: github/dependency-review-action@v3
- name: SAST Scanning
  uses: github/codeql-action/analyze@v2
- name: Secret Detection
  uses: trufflesecurity/trufflehog@main
- name: Container Scanning
  uses: aquasecurity/trivy-action@master

4. 实施模式

4.1 安全工作流结构

name: Secure Build Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

# 关键: 限制默认权限
permissions:
  contents: read

jobs:
  security-scan:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write
    steps:
      - uses: actions/checkout@v4
      - uses: github/codeql-action/analyze@v2
      - uses: actions/dependency-review-action@v3
        if: github.event_name == 'pull_request'

  build:
    needs: security-scan
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
        with:
          node-version: '20'
      - run: npm run build

📚 参见 references/advanced-patterns.md 用于发布作业和环境保护。

4.2 秘密管理

jobs:
  deploy-staging:
    environment: staging
    env:
      API_KEY: ${{ secrets.STAGING_API_KEY }}

  deploy-production:
    environment: production
    env:
      API_KEY: ${{ secrets.PRODUCTION_API_KEY }}

# 正确: 使用环境变量
- name: Use Secret
  env:
    API_KEY: ${{ secrets.API_KEY }}
  run: curl -H "Authorization: Bearer $API_KEY" https://api.example.com

永不: echo ${{ secrets.API_KEY }} - 在日志中暴露!

4.3 桌面应用程序的代码签名

Windows签名核心模式:

- name: Import Certificate
  env:
    CERTIFICATE_BASE64: ${{ secrets.WINDOWS_CERTIFICATE }}
    CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
  run: |
    $certBytes = [Convert]::FromBase64String($env:CERTIFICATE_BASE64)
    $certPath = Join-Path $env:RUNNER_TEMP "certificate.pfx"
    [IO.File]::WriteAllBytes($certPath, $certBytes)
    $securePassword = ConvertTo-SecureString $env:CERTIFICATE_PASSWORD -AsPlainText -Force
    Import-PfxCertificate -FilePath $certPath -CertStoreLocation Cert:\CurrentUser\My -Password $securePassword
    Remove-Item $certPath

macOS签名核心模式:

- name: Import Apple Certificates
  env:
    APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
    APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
    KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
  run: |
    security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
    security default-keychain -s build.keychain
    security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
    echo "$APPLE_CERTIFICATE" | base64 --decode > certificate.p12
    security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
    security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
    rm certificate.p12

📚 参见 references/security-examples.md 用于完整的签名工作流和公证。

4.4 OIDC认证(无密钥)

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Authenticate to AWS
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789:role/GitHubActionsRole
          aws-region: us-east-1
          # 不需要秘密!使用OIDC令牌

📚 参见 references/security-examples.md 用于GCP和Azure OIDC模式。


5. 安全标准

5.1 关键漏洞

CVE 严重性 缓解措施
CVE-2024-23897 关键 (9.8) 更新Jenkins,限制CLI
CVE-2023-49291 关键 (9.8) 通过SHA固定操作
CVE-2025-30066 高 (8.6) 审计tj-actions使用

关键洞察: 通过第三方操作的供应链攻击是主要威胁。始终通过SHA固定并审计操作来源。

5.2 OWASP CI/CD Top 10 总结

风险 关键控制
流程控制不足 必需审查、环境保护
身份/访问不足 OIDC、最小权限、MFA
依赖链滥用 通过SHA固定、扫描依赖
毒化管道执行 保护工作流文件、限制触发器
凭据卫生不足 轮换秘密、作用域狭窄

5.3 供应链安全

# 通过SHA固定操作(不是标签)
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0

# 生成SBOM以增加透明度
- name: Generate SBOM
  uses: anchore/sbom-action@v0
  with:
    artifact-name: sbom.spdx.json

📚 参见 references/security-examples.md 用于完整的供应链保护。


6. 测试标准

# 在PR中测试工作流更改
on:
  pull_request:
    paths:
      - '.github/workflows/**'

jobs:
  validate-workflows:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Validate YAML
        run: |
          pip install yamllint
          yamllint .github/workflows/
      - name: Check for secrets in logs
        run: grep -r 'echo.*secrets\.' .github/workflows/ && exit 1 || true
      - name: Verify SHA pinning
        run: grep -E 'uses:.*@[^a-f0-9]' .github/workflows/ && exit 1 || true

7. 实施工作流(TDD)

步骤1: 首先编写失败测试

在创建或修改工作流之前,编写验证预期行为的测试:

# .github/workflows/test-workflows.yml
name: Validate Workflows
on: [push, pull_request]

jobs:
  test-workflow-syntax:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install actionlint
        run: |
          bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
      - name: Lint workflows
        run: ./actionlint -color

  test-security-compliance:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Check permissions are explicit
        run: |
          for f in .github/workflows/*.yml; do
            if ! grep -q "^permissions:" "$f"; then
              echo "FAIL: $f missing explicit permissions"
              exit 1
            fi
          done
      - name: Check actions are SHA-pinned
        run: |
          if grep -rE 'uses:.*@v[0-9]' .github/workflows/; then
            echo "FAIL: Found unpinned actions"
            exit 1
          fi

步骤2: 实施最小通过

创建工作流配置以满足测试要求:

# .github/workflows/build.yml
name: Build
on: [push]
permissions:
  contents: read
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
      - run: npm ci && npm run build

步骤3: 重构和优化

添加缓存、并行化和安全增强:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
      - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci && npm run build

步骤4: 运行完整验证

# 本地验证
actionlint .github/workflows/
yamllint .github/workflows/

# 安全检查
grep -rE 'uses:.*@v[0-9]' .github/workflows/ && echo "FAIL: Unpinned actions" || echo "PASS"
grep -r 'echo.*secrets\.' .github/workflows/ && echo "FAIL: Secret exposure" || echo "PASS"

# 推送并验证CI通过
git push && gh run watch

8. 性能模式

8.1 缓存策略

好 - 具有适当键的积极缓存:

- uses: actions/cache@v4
  with:
    path: |
      ~/.npm
      node_modules
      ~/.cargo/registry
      target
    key: ${{ runner.os }}-deps-${{ hashFiles('**/package-lock.json', '**/Cargo.lock') }}
    restore-keys: |
      ${{ runner.os }}-deps-

坏 - 无缓存或差缓存键:

# 缺少缓存 - 每次构建都慢
- run: npm ci
- run: cargo build

8.2 并行作业

好 - 独立作业并行运行:

jobs:
  lint:
    runs-on: ubuntu-latest
    steps: [...]

  test-unit:
    runs-on: ubuntu-latest
    steps: [...]

  test-e2e:
    runs-on: ubuntu-latest
    steps: [...]

  build:
    needs: [lint, test-unit, test-e2e]  # 等待所有并行作业
    runs-on: ubuntu-latest

坏 - 可以并行但顺序的作业:

jobs:
  lint:
    runs-on: ubuntu-latest
  test-unit:
    needs: lint  # 不必要的依赖
  test-e2e:
    needs: test-unit  # 不必要的依赖

8.3 工件优化

好 - 压缩和限制工件保留:

- name: Upload artifacts
  uses: actions/upload-artifact@v4
  with:
    name: build-output
    path: dist/
    retention-days: 7
    compression-level: 9

坏 - 大未压缩工件,保留时间长:

- uses: actions/upload-artifact@v4
  with:
    name: everything
    path: .  # 上传整个仓库
    retention-days: 90

8.4 增量构建

好 - 跳过未更改组件:

- name: Check for changes
  id: changes
  uses: dorny/paths-filter@v2
  with:
    filters: |
      frontend:
        - 'src/frontend/**'
      backend:
        - 'src/backend/**'

- name: Build frontend
  if: steps.changes.outputs.frontend == 'true'
  run: npm run build

- name: Build backend
  if: steps.changes.outputs.backend == 'true'
  run: cargo build --release

坏 - 总是重建一切:

- run: npm run build
- run: cargo build --release
# 即使那些组件没有更改也运行

8.5 条件工作流

好 - 仅在需要时运行昂贵作业:

on:
  push:
    branches: [main]
    paths:
      - 'src/**'
      - 'Cargo.toml'
      - 'package.json'

jobs:
  expensive-test:
    if: contains(github.event.head_commit.message, '[full-test]') || github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest

坏 - 每次推送都运行一切:

on: [push]  # 在每个分支、每次提交时触发
jobs:
  full-e2e-suite:  # 昂贵作业不必要地运行
    runs-on: ubuntu-latest

9. 常见错误和反模式

过度许可令牌

# 错误
permissions: write-all

# 正确
permissions:
  contents: read

未固定操作

# 错误: 标签/分支可以移动
- uses: actions/checkout@v4
- uses: actions/checkout@main

# 正确: SHA不可变
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608

秘密暴露

# 错误: 命令行中的秘密
- run: curl -u user:${{ secrets.TOKEN }} https://api.example.com

# 正确: 环境变量中的秘密
- env:
    TOKEN: ${{ secrets.TOKEN }}
  run: curl -u "user:$TOKEN" https://api.example.com

不安全的pull_request_target

# 危险: 在不可信代码上以写权限运行
on:
  pull_request_target:
jobs:
  build:
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.head.sha }}  # 不可信!
      - run: npm install  # 可以执行恶意脚本

📚 参见 references/threat-model.md 用于安全模式和信任边界。


10. 预实施检查清单

阶段1: 编写代码前

  • [ ] 审查现有工作流以遵循模式
  • [ ] 识别安全要求(秘密、签名、OIDC)
  • [ ] 规划依赖的缓存策略
  • [ ] 定义作业并行化结构
  • [ ] 检查 references/threat-model.md 用于安全考虑

阶段2: 实施期间

  • [ ] 默认权限: contents: read
  • [ ] 所有作业具有显式最小权限
  • [ ] 所有操作通过SHA固定(不是标签)
  • [ ] 秘密通过环境变量传递
  • [ ] 缓存配置具有适当键
  • [ ] 作业在独立时并行化
  • [ ] 路径过滤器用于条件执行

阶段3: 提交前

  • [ ] 在所有工作流上运行 actionlint
  • [ ] 运行 yamllint 用于语法验证
  • [ ] 验证没有 echo.*secrets 模式
  • [ ] 验证没有未固定操作(@v* 模式)
  • [ ] 如果可能,使用 act 本地测试工作流
  • [ ] SBOM生成配置用于发布
  • [ ] 生产的环境具有保护规则
  • [ ] 秘密轮换文档化

11. 总结

您的目标是创建CI/CD管道,它们是:

  • 安全: 最小权限、固定依赖、保护秘密
  • 可审计: 记录操作、SBOM、签署工件
  • 弹性: 纵深防御、作业间隔离

CI/CD管道是高价值目标,因为它们可以访问签名密钥和凭据,可以修改生产工件,并在代码更改时自动运行。

安全提醒: 始终通过SHA固定操作。始终使用最小权限。始终保护秘密免于暴露。有疑问时,咨询 references/threat-model.md 用于攻击场景。