Criar segredos criptografados
Os fluxos de trabalho do GitHub Actions geralmente precisam de acesso a informações confidenciais, como chaves de API, senhas, certificados e tokens. O GitHub fornece segredos criptografados para armazenar e acessar com segurança esses dados confidenciais sem expô-los em seus arquivos de código ou fluxo de trabalho.
Noções básicas sobre segredos do GitHub
Os segredos do GitHub são variáveis de ambiente criptografadas que você pode criar em diferentes níveis em sua organização do GitHub. Depois de criados, os segredos são criptografados e só podem ser descriptografados durante a execução do fluxo de trabalho em contextos autorizados.
Principais características dos segredos do GitHub:
- Armazenamento criptografado: todos os segredos são criptografados usando criptografia padrão do setor
- Acesso controlado: somente fluxos de trabalho autorizados podem acessar segredos
- Mascarados em logs: valores secretos são automaticamente mascarados em logs de fluxo de trabalho
- Imutável: uma vez criados, os valores secretos não podem ser exibidos, apenas substituídos
Escopos secretos e hierarquia
Segredos no nível do repositório
Os segredos do repositório estão disponíveis apenas para fluxos de trabalho nesse repositório específico:
# 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
Segredos no nível da organização
Os segredos da organização podem ser compartilhados em vários repositórios com acesso controlado:
# 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"
Segredos no nível do ambiente
Os segredos do ambiente fornecem controle refinado para ambientes de implantação:
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
Criando e gerenciando segredos
Configuração de segredos do repositório
Navegue até as configurações do repositório:
- Vá para o repositório no GitHub
- Clique na guia Configurações
- Selecionar Segredos e variáveis>Ações
Criar novo segredo do repositório:
Name: PRODUCTION_API_KEY Value: your-actual-api-key-valueUse no fluxo de trabalho:
env: API_KEY: ${{ secrets.PRODUCTION_API_KEY }}
Gerenciamento de segredos da organização
# 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" .
Políticas de acesso a segredos da organização:
- Todos os repositórios: disponíveis para todos os repositórios na organização
- Repositórios privados: disponíveis apenas para repositórios privados
- Repositórios selecionados: disponíveis apenas para repositórios escolhidos especificamente
Segredos de ambiente com regras de proteção
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
Práticas recomendadas de segurança para segredos
Convenções de nomenclatura secretas
# 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
Princípio de privilégios mínimos
# 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"
Rotação de segredo e gerenciamento de ciclo de vida
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
Uso de segredo condicional
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
Padrões de segredo avançados
Segredos de vários valores (configuração 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_*
Herança e composição secretas
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();"
Validação e teste de códigos secretos
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
Armadilhas comuns e considerações de segurança
Evitando a exposição secreta
# 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"
Tratamento de erro adequado
- 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"
Gerenciamento de escopo de segredo
# 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
O gerenciamento adequado de segredos é crucial para manter a segurança dos seus pipelines de CI/CD. Sempre siga o princípio de privilégios mínimos, use a nomenclatura descritiva e implemente a validação adequada para garantir que seus segredos permaneçam seguros, permitindo recursos de automação avançados.