Appearance
GitHub Actions密钥管理
密钥管理是GitHub Actions安全的核心组成部分,用于存储和管理敏感信息,如API密钥、密码、证书等。本文档将详细介绍如何安全地管理密钥以及最佳实践。
密钥基础概念
什么是密钥(Secrets)
密钥是加密存储的敏感值,只能在GitHub Actions工作流中访问。密钥在日志中会被自动屏蔽,不会以明文形式显示。
yaml
# .github/workflows/example.yml
name: Example with Secrets
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Use secret in step
run: |
echo "Using API key for deployment..."
# 实际使用中,密钥不会在日志中显示
env:
API_KEY: ${{ secrets.API_KEY }}
DATABASE_PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
密钥的加密和存储
GitHub使用AES-256加密算法对密钥进行加密存储,并且只有在工作流执行时才解密。密钥在传输过程中使用TLS加密。
创建和管理密钥
在仓库设置中创建密钥
密钥可以通过GitHub界面创建:
- 进入仓库设置(Settings)
- 选择"Secrets and variables"
- 选择"Actions"
- 点击"New repository secret"
- 输入密钥名称和值
使用GitHub CLI创建密钥
bash
# 安装GitHub CLI后
gh secret set API_KEY -b"your-api-key-value"
gh secret set DATABASE_URL -b"postgresql://user:pass@host:port/db"
gh secret set SSH_PRIVATE_KEY -b"$(cat ~/.ssh/id_rsa)"
在工作流中使用密钥
yaml
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy using secrets
run: |
# 使用密钥进行部署操作
curl -X POST \
-H "Authorization: Bearer ${{ secrets.API_KEY }}" \
-H "Content-Type: application/json" \
-d '{"app":"my-app","version":"1.0.0"}' \
https://api.example.com/deploy
env:
API_KEY: ${{ secrets.API_KEY }}
密钥作用域
仓库级密钥
仓库级密钥只能在特定仓库中使用:
yaml
# .github/workflows/repo-specific.yml
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Use repository secret
run: echo "Using repo-specific secret"
env:
REPO_SECRET: ${{ secrets.REPO_SECRET }}
环境级密钥
环境级密钥只在特定环境中可用:
yaml
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging # 环境级密钥在此环境中可用
steps:
- name: Deploy to staging
run: echo "Deploying with environment secrets"
env:
STAGING_API_KEY: ${{ secrets.STAGING_API_KEY }}
deploy-production:
runs-on: ubuntu-latest
environment: production # 环境级密钥在此环境中可用
steps:
- name: Deploy to production
run: echo "Deploying with production secrets"
env:
PROD_API_KEY: ${{ secrets.PROD_API_KEY }}
组织级密钥
组织级密钥可以在组织的所有仓库中使用(需要适当权限):
yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Use organization secret
run: echo "Using organization-wide secret"
env:
ORG_SECRET: ${{ secrets.ORG_SECRET }}
密钥安全最佳实践
1. 最小权限原则
只为工作流提供必需的密钥:
yaml
# 好的做法:只提供必需的密钥
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Build only
run: npm run build
# 不需要任何密钥,因为构建不需要敏感信息
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy with minimal secrets
run: ./deploy.sh
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }} # 只提供部署必需的密钥
2. 密钥轮换
定期更换密钥:
yaml
# 在密钥描述中记录轮换日期
# "API_KEY - Last rotated: 2023-12-01, next rotation: 2024-03-01"
jobs:
security-check:
runs-on: ubuntu-latest
steps:
- name: Check secret age
run: |
# 检查密钥是否需要轮换的逻辑
echo "Checking if secrets need rotation..."
3. 密钥验证
在使用密钥前验证其存在性:
yaml
jobs:
validate-secrets:
runs-on: ubuntu-latest
steps:
- name: Validate required secrets
run: |
if [ -z "$API_KEY" ]; then
echo "Error: API_KEY is not set"
exit 1
fi
if [ -z "$DATABASE_PASSWORD" ]; then
echo "Error: DATABASE_PASSWORD is not set"
exit 1
fi
echo "All required secrets are present"
env:
API_KEY: ${{ secrets.API_KEY }}
DATABASE_PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
密钥类型和用途
API密钥
yaml
jobs:
api-call:
runs-on: ubuntu-latest
steps:
- name: Make API call
run: |
curl -X GET \
-H "Authorization: Bearer ${{ secrets.API_KEY }}" \
-H "Content-Type: application/json" \
https://api.example.com/data
数据库凭证
yaml
jobs:
database-operation:
runs-on: ubuntu-latest
steps:
- name: Connect to database
run: |
# 使用数据库凭证连接数据库
psql -h ${{ secrets.DB_HOST }} \
-U ${{ secrets.DB_USER }} \
-d ${{ secrets.DB_NAME }} \
-c "SELECT version();"
env:
PGPASSWORD: ${{ secrets.DB_PASSWORD }}
SSH密钥
yaml
jobs:
deploy-via-ssh:
runs-on: ubuntu-latest
steps:
- name: Setup SSH key
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H "${{ secrets.HOST }}" >> ~/.ssh/known_hosts
# 使用SSH进行部署
ssh ${{ secrets.USER }}@${{ secrets.HOST }} "cd ${{ secrets.REMOTE_PATH }} && git pull"
Docker凭证
yaml
jobs:
docker-build-push:
runs-on: ubuntu-latest
steps:
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
run: |
docker build -t myapp:${{ github.sha }} .
docker push myapp:${{ github.sha }}
密钥的条件使用
环境条件
yaml
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy based on environment
run: |
if [ "$GITHUB_REF" = "refs/heads/main" ]; then
# 生产环境使用生产密钥
API_KEY="${{ secrets.PROD_API_KEY }}"
elif [ "$GITHUB_REF" = "refs/heads/develop" ]; then
# 开发环境使用开发密钥
API_KEY="${{ secrets.DEV_API_KEY }}"
else
# 其他环境使用测试密钥
API_KEY="${{ secrets.TEST_API_KEY }}"
fi
echo "Using API key for environment: $GITHUB_REF"
env:
API_KEY: ${{ secrets.ENV_API_KEY }}
事件条件
yaml
jobs:
conditional-secrets:
runs-on: ubuntu-latest
steps:
- name: Use secrets conditionally
run: |
if [ "$GITHUB_EVENT_NAME" = "push" ]; then
echo "Push event - using deployment secrets"
DEPLOY_SECRET="${{ secrets.DEPLOY_SECRET }}"
elif [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
echo "PR event - using test secrets"
DEPLOY_SECRET="${{ secrets.TEST_SECRET }}"
fi
env:
GITHUB_EVENT_NAME: ${{ github.event_name }}
密钥安全检测
检测密钥泄露
yaml
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # 获取完整历史以检查所有提交
- name: Scan for secrets in code
run: |
# 使用truffleHog或其他工具扫描密钥泄露
# truffleHog --regex --entropy=False .
echo "Scanning for potential secret leaks..."
# 检查代码中是否包含密钥字面量
if git grep -l "secret\|password\|token\|key" -- "*.yml" "*.yaml" "*.json" "*.js" "*.py"; then
echo "Potential secrets found in code. Please review."
exit 1
fi
验证密钥格式
yaml
jobs:
validate-secret-format:
runs-on: ubuntu-latest
steps:
- name: Validate secret format
run: |
# 验证API密钥格式
API_KEY="${{ secrets.API_KEY }}"
if [[ ! "$API_KEY" =~ ^[A-Za-z0-9_\-]{32,}$ ]]; then
echo "API key format is invalid"
exit 1
fi
# 验证邮箱格式的密钥
EMAIL_TOKEN="${{ secrets.EMAIL_TOKEN }}"
if [[ ! "$EMAIL_TOKEN" =~ ^[A-Za-z0-9+/]{20,}={0,2}$ ]]; then
echo "Email token format is invalid"
exit 1
fi
echo "All secrets have valid formats"
密钥管理工具
使用密钥管理服务
yaml
jobs:
use-external-secret:
runs-on: ubuntu-latest
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Get secret from AWS Secrets Manager
run: |
SECRET_VALUE=$(aws secretsmanager get-secret-value \
--secret-id my-app/production/api-key \
--query SecretString \
--output text)
echo "SECRET_VALUE=$SECRET_VALUE" >> $GITHUB_ENV
密钥的分层管理
yaml
# 使用GitHub Variables存储非敏感配置
# 使用GitHub Secrets存储敏感信息
env:
APP_VERSION: ${{ vars.APP_VERSION }} # 非敏感
LOG_LEVEL: ${{ vars.LOG_LEVEL }} # 非敏感
API_ENDPOINT: ${{ vars.API_ENDPOINT }} # 非敏感
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy with layered configuration
run: |
echo "Deploying version $APP_VERSION"
echo "API endpoint: $API_ENDPOINT"
echo "Log level: $LOG_LEVEL"
# 使用敏感密钥
env:
API_KEY: ${{ secrets.API_KEY }} # 敏感信息
DB_PASSWORD: ${{ secrets.DB_PASSWORD }} # 敏感信息
密钥轮换策略
自动化轮换
yaml
# 可以创建一个定期运行的工作流来检查密钥轮换需求
name: Secret Rotation Check
on:
schedule:
- cron: '0 0 1 * *' # 每月1号执行
workflow_dispatch:
jobs:
check-rotation:
runs-on: ubuntu-latest
steps:
- name: Check secret age
run: |
echo "Checking if secrets need rotation..."
# 实现密钥轮换检查逻辑
# 可以通过API调用或外部服务来管理密钥轮换
密钥版本管理
yaml
# 使用版本化的密钥名称
jobs:
use-versioned-secret:
runs-on: ubuntu-latest
steps:
- name: Use current version of secret
run: |
# 使用最新版本的密钥
echo "Using API key version 2"
env:
API_KEY: ${{ secrets.API_KEY_V2 }}
- name: Fallback to previous version
run: |
# 如果新版本不可用,回退到旧版本
echo "Using fallback secret"
env:
API_KEY: ${{ secrets.API_KEY_V1 }}
if: env.API_KEY_V2 == ''
审计和监控
密钥访问日志
yaml
jobs:
audit-secret-access:
runs-on: ubuntu-latest
steps:
- name: Log secret access
run: |
echo "Workflow: $GITHUB_WORKFLOW"
echo "Run ID: $GITHUB_RUN_ID"
echo "Actor: $GITHUB_ACTOR"
echo "Repository: $GITHUB_REPOSITORY"
echo "Timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo "Secret access logged"
env:
# 实际的密钥不会被记录,只记录访问行为
AUDIT_LOG_TOKEN: ${{ secrets.AUDIT_LOG_TOKEN }}
密钥使用监控
yaml
# 创建专门的监控工作流
name: Secret Usage Monitoring
on:
workflow_run:
workflows: ["CI/CD Pipeline"]
types: [completed]
jobs:
monitor-secrets:
runs-on: ubuntu-latest
steps:
- name: Monitor secret usage
run: |
echo "Workflow ${{ github.event.workflow_run.name }} completed"
echo "Status: ${{ github.event.workflow_run.conclusion }}"
# 记录和监控密钥使用情况
最佳实践总结
1. 分类管理
yaml
# 将密钥按用途分类
# - 部署密钥:DEPLOY_TOKEN, SSH_PRIVATE_KEY
# - API密钥:API_KEY, API_SECRET
# - 数据库密钥:DB_PASSWORD, DB_SSL_CERT
# - 服务密钥:SERVICE_ACCOUNT_KEY, ACCESS_TOKEN
2. 文档记录
yaml
# 在密钥描述中记录以下信息:
# - 密钥用途
# - 创建日期
# - 预期轮换日期
# - 相关服务/系统
# - 访问权限要求
3. 安全检查清单
yaml
# 密钥安全检查清单:
# [ ] 密钥不在代码中硬编码
# [ ] 密钥不在提交消息中
# [ ] 密钥不在日志中明文显示
# [ ] 密钥具有最小必要权限
# [ ] 密钥定期轮换
# [ ] 密钥访问受到监控
通过遵循这些密钥管理最佳实践,可以确保GitHub Actions工作流的安全性,防止敏感信息泄露,并建立可靠的自动化流程。