暗号化されたシークレットを作成する

完了

GitHub Actions ワークフローでは、多くの場合、API キー、パスワード、証明書、トークンなどの機密情報にアクセスする必要があります。 GitHub には、暗号化されたシークレットが用意されており、コードやワークフロー ファイルに公開することなく、この機密データを安全に格納してアクセスできます。

GitHub シークレットについて

GitHub シークレットは暗号化された環境変数であり、GitHub 組織内のさまざまなレベルで作成できます。 作成されると、シークレットは暗号化され、承認されたコンテキストでのワークフローの実行中にのみ復号化できます。

GitHub シークレットの主な特性:

  • 暗号化されたストレージ: すべてのシークレットは業界標準の暗号化を使用して暗号化されます
  • アクセスの制御: 承認されたワークフローのみがシークレットにアクセスできます
  • ログでマスク: シークレット値はワークフロー ログで自動的にマスクされます
  • 不変: 作成されると、シークレット値を表示できず、置き換えるだけです

シークレットのスコープと階層

リポジトリ レベルのシークレット

リポジトリ シークレットは、その特定のリポジトリ内のワークフローでのみ使用できます。

# Using repository secret in workflow
name: Deploy Application

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to production
        env:
          API_KEY: ${{ secrets.PRODUCTION_API_KEY }}
          DATABASE_URL: ${{ secrets.DATABASE_CONNECTION_STRING }}
        run: |
          echo "Deploying with API key starting with: ${API_KEY:0:8}..."
          ./deploy.sh

Organization レベルのシークレット

組織のシークレットは、アクセスが制御された複数のリポジトリ間で共有できます。

# Organization secret with repository access control
name: Shared CI Pipeline

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Run integration tests
        env:
          # This secret is available to authorized repositories
          SHARED_TEST_API_KEY: ${{ secrets.INTEGRATION_TEST_API_KEY }}
        run: |
          npm test -- --api-key="$SHARED_TEST_API_KEY"

環境レベルのシークレット

環境シークレットは、デプロイ環境をきめ細かく制御します。

name: Multi-Environment Deploy

on:
  push:
    branches: [main, develop]

jobs:
  deploy-staging:
    if: github.ref == 'refs/heads/develop'
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - name: Deploy to staging
        env:
          # Environment-specific secrets
          DEPLOYMENT_KEY: ${{ secrets.STAGING_DEPLOY_KEY }}
          API_ENDPOINT: ${{ secrets.STAGING_API_URL }}
        run: ./deploy.sh staging

  deploy-production:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Deploy to production
        env:
          DEPLOYMENT_KEY: ${{ secrets.PRODUCTION_DEPLOY_KEY }}
          API_ENDPOINT: ${{ secrets.PRODUCTION_API_URL }}
        run: ./deploy.sh production

シークレットの作成と管理

リポジトリ シークレットのセットアップ

  1. リポジトリの設定に移動します

    • GitHub でリポジトリに移動する
    • [ 設定] タブを クリックする
    • シークレットと変数の選択>Actions
  2. 新しいリポジトリ シークレットを作成します。

    Name: PRODUCTION_API_KEY
    Value: your-actual-api-key-value
    
  3. ワークフローでの使用:

    env:
      API_KEY: ${{ secrets.PRODUCTION_API_KEY }}
    

組織のシークレット管理

# Example of organization secret usage with access policies
name: Organization-wide CI

on: [push]

jobs:
  security-scan:
    runs-on: ubuntu-latest
    steps:
      - name: Security vulnerability scan
        env:
          # Organization secret with controlled repository access
          SECURITY_SCAN_TOKEN: ${{ secrets.ORG_SECURITY_SCAN_TOKEN }}
        run: |
          security-scanner --token="$SECURITY_SCAN_TOKEN" .

組織のシークレット アクセス ポリシー:

  • すべてのリポジトリ: 組織内のすべてのリポジトリで使用可能
  • プライベート リポジトリ: プライベート リポジトリでのみ使用できます
  • 選択したリポジトリ: 特に選択したリポジトリでのみ使用できます

保護規則を使用した環境シークレット

name: Protected Production Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://myapp.production.com
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Deploy with environment protection
        env:
          # Protected by environment rules (approvals, wait timers)
          PROD_DEPLOY_TOKEN: ${{ secrets.PRODUCTION_DEPLOY_TOKEN }}
          PROD_DB_PASSWORD: ${{ secrets.PRODUCTION_DATABASE_PASSWORD }}
        run: |
          echo "Deploying to production environment..."
          ./scripts/deploy-production.sh

シークレットのセキュリティのベスト プラクティス

シークレットの名前付け規則

# Good: Clear, descriptive names
secrets:
  PRODUCTION_API_KEY
  STAGING_DATABASE_URL
  AWS_ACCESS_KEY_ID
  AZURE_CLIENT_SECRET
  DOCKER_REGISTRY_TOKEN

# Avoid: Vague or generic names
secrets:
  KEY
  PASSWORD
  TOKEN
  SECRET

最小特権の原則

# Good: Specific secrets for specific purposes
name: Database Migration

jobs:
  migrate:
    runs-on: ubuntu-latest
    steps:
      - name: Run database migration
        env:
          # Read-only database connection for migrations
          DB_MIGRATION_URL: ${{ secrets.DB_MIGRATION_CONNECTION }}
        run: |
          migrate up --database-url="$DB_MIGRATION_URL"

  backup:
    runs-on: ubuntu-latest
    steps:
      - name: Create database backup
        env:
          # Backup-specific credentials with limited scope
          BACKUP_ACCESS_KEY: ${{ secrets.DB_BACKUP_ACCESS_KEY }}
        run: |
          backup-db --credentials="$BACKUP_ACCESS_KEY"

シークレットローテーションとライフサイクル管理

name: Secret Health Check

on:
  schedule:
    - cron: "0 6 * * 1" # Weekly on Monday at 6 AM

jobs:
  check-secret-health:
    runs-on: ubuntu-latest
    steps:
      - name: Test API key validity
        env:
          API_KEY: ${{ secrets.PRODUCTION_API_KEY }}
        run: |
          # Test if API key is still valid
          response=$(curl -s -o /dev/null -w "%{http_code}" \
            -H "Authorization: Bearer $API_KEY" \
            https://api.example.com/health)
            
          if [ "$response" != "200" ]; then
            echo "API key may be expired or invalid"
            # Create issue or notify team
            gh issue create --title "API Key Health Check Failed" \
              --body "The production API key failed health check. Response code: $response"
          else
            echo "API key is healthy"
          fi

条件付きシークレットの使用

name: Flexible Secret Usage

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Run tests
        env:
          # Use different secrets based on event type
          API_KEY: ${{ github.event_name == 'push' && secrets.INTEGRATION_API_KEY || secrets.TESTING_API_KEY }}
          DATABASE_URL: ${{ github.ref == 'refs/heads/main' && secrets.PROD_DB_URL || secrets.TEST_DB_URL }}
        run: |
          echo "Running tests with appropriate credentials..."
          npm test

高度なシークレット パターン

複数値シークレット (JSON 構成)

name: Complex Configuration

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Parse complex secret
        env:
          # Store complex configuration as JSON in secret
          AWS_CONFIG: ${{ secrets.AWS_DEPLOYMENT_CONFIG }}
        run: |
          # Parse JSON secret
          echo "$AWS_CONFIG" | jq -r '.access_key_id' > /tmp/aws_key
          echo "$AWS_CONFIG" | jq -r '.secret_access_key' > /tmp/aws_secret
          echo "$AWS_CONFIG" | jq -r '.region' > /tmp/aws_region

          # Configure AWS CLI
          aws configure set aws_access_key_id "$(cat /tmp/aws_key)"
          aws configure set aws_secret_access_key "$(cat /tmp/aws_secret)"
          aws configure set default.region "$(cat /tmp/aws_region)"

          # Clean up temporary files
          rm -f /tmp/aws_*

秘密の継承と合成

name: Composed Secrets

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Build connection string
        env:
          DB_HOST: ${{ secrets.DATABASE_HOST }}
          DB_USER: ${{ secrets.DATABASE_USER }}
          DB_PASS: ${{ secrets.DATABASE_PASSWORD }}
          DB_NAME: ${{ secrets.DATABASE_NAME }}
        run: |
          # Compose connection string from individual secrets
          CONNECTION_STRING="postgresql://$DB_USER:$DB_PASS@$DB_HOST:5432/$DB_NAME"

          # Use composed string (never log it)
          echo "Connecting to database..."
          psql "$CONNECTION_STRING" -c "SELECT version();"

シークレットの検証とテスト

name: Secret Validation

jobs:
  validate-secrets:
    runs-on: ubuntu-latest
    steps:
      - name: Validate API credentials
        env:
          API_KEY: ${{ secrets.API_KEY }}
          API_SECRET: ${{ secrets.API_SECRET }}
        run: |
          # Test API credentials without exposing values
          if [ -z "$API_KEY" ] || [ -z "$API_SECRET" ]; then
            echo "Missing required API credentials"
            exit 1
          fi

          # Test key format (without revealing the key)
          if [[ ${#API_KEY} -lt 32 ]]; then
            echo "API key appears to be invalid (too short)"
            exit 1
          fi

          # Test authentication
          response=$(curl -s -w "%{http_code}" -o /dev/null \
            -H "Authorization: Bearer $API_KEY" \
            https://api.example.com/auth/test)
            
          if [ "$response" = "200" ]; then
            echo "API credentials validated successfully"
          else
            echo "API credential validation failed (HTTP $response)"
            exit 1
          fi

一般的な落とし穴とセキュリティに関する考慮事項

秘密の露出の回避

# DON'T: Never echo or log secrets directly
- name: Bad secret usage
  env:
    API_KEY: ${{ secrets.API_KEY }}
  run: |
    echo "Using API key: $API_KEY"  # This will expose the secret!

# DO: Use secrets safely without exposure
- name: Safe secret usage
  env:
    API_KEY: ${{ secrets.API_KEY }}
  run: |
    # Use the secret without logging it
    curl -H "Authorization: Bearer $API_KEY" https://api.example.com/data
    echo "API request completed successfully"

適切なエラー処理

- name: Secure error handling
  env:
    DATABASE_PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
  run: |
    # Set error handling to avoid secret leaks
    set +x  # Disable command echoing

    if ! psql "postgresql://user:$DATABASE_PASSWORD@host/db" -c "SELECT 1"; then
      # Log error without exposing secret
      echo "Database connection failed"
      exit 1
    fi

    echo "Database connection successful"

シークレット スコープの管理

# Good: Limit secret scope to specific steps
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        # No secrets available here

      - name: Deploy application
        env:
          DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }} # Secret only in this step
        run: |
          ./deploy.sh

      - name: Run post-deploy tests
        # No secrets available here
        run: |
          ./test.sh

CI/CD パイプラインのセキュリティを維持するには、適切なシークレット管理が重要です。 常に最小限の特権の原則に従い、わかりやすい名前付けを使用し、適切な検証を実装して、強力な自動化機能を有効にしながらシークレットをセキュリティで保護します。