CI/CD Security: Proteggere il Processo di Build e Deploy
La pipeline CI/CD e il cuore del processo di delivery del software. Se un attaccante compromette la pipeline, può iniettare codice malevolo in ogni build e deploy successivo. La sicurezza della pipeline non riguarda solo cosa la pipeline testa, ma come la pipeline stessa e protetta da manomissioni.
In questo articolo esploreremo le pratiche per rendere sicura la pipeline CI/CD: dal branch protection ai signed commits, dall'OIDC al least privilege, fino all'audit logging e all'approval workflow per i deploy in produzione.
Cosa Imparerai
- Threat model della pipeline CI/CD
- Branch protection e code review enforcement
- OIDC per l'autenticazione senza secret statici
- Least privilege per i runner e i workflow
- Signed commits e verificabilita del codice
- Deployment approval workflows
Threat Model della Pipeline CI/CD
Per proteggere la pipeline, dobbiamo capire dove sono le superfici di attacco:
- Codice sorgente: un contributor malevolo inietta codice in una PR
- Dipendenze: una dipendenza compromessa viene installata durante il build
- Pipeline configuration: modifica dei workflow file per esfiltrare secret
- Runner: compromissione del build agent per persistenza nell'infrastruttura
- Artifact: sostituzione dell'artifact build con uno malevolo
- Deploy credentials: furto delle credenziali di deploy per accesso diretto all'infrastruttura
Branch Protection Rules
Le branch protection rules sono la prima linea di difesa. Garantiscono che nessun codice raggiunga il branch principale senza review e controlli automatici.
Configurazione Raccomandata
| Regola | Impostazione | Motivazione |
|---|---|---|
| Require PR reviews | Minimo 2 approvazioni | Four-eyes principle |
| Dismiss stale reviews | Abilitato | Invalidare approvazioni dopo push |
| Require status checks | SAST, SCA, test, lint | Gate automatici obbligatori |
| Require signed commits | Abilitato | Verificabilita del contributor |
| Restrict push access | Solo bot CI/CD | Nessun push diretto al main |
| Require linear history | Abilitato | Cronologia pulita e verificabile |
OIDC: Autenticazione Senza Secret Statici
OpenID Connect (OIDC) permette ai workflow CI/CD di autenticarsi con i cloud provider senza utilizzare secret statici (API key, service account key). Il workflow ottiene un token temporaneo basato sull'identità del repository e del branch.
# .github/workflows/deploy-oidc.yml
name: Deploy with OIDC
on:
push:
branches: [main]
permissions:
id-token: write # Necessario per OIDC
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure AWS Credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-deploy
aws-region: eu-west-1
# Nessun secret! Il token OIDC viene usato automaticamente
- name: Deploy to AWS
run: |
aws s3 sync dist/ s3://my-bucket/
aws cloudfront create-invalidation --distribution-id E123 --paths "/*"
Least Privilege per Workflow
Ogni workflow GitHub Actions ha permessi predefiniti che possono essere troppo ampi. Il principio del least privilege richiede di limitare i permessi al minimo necessario per ogni job:
# Permessi globali restrittivi
permissions:
contents: read # Solo lettura del repository
jobs:
test:
runs-on: ubuntu-latest
# Nessun permesso aggiuntivo per i test
steps:
- uses: actions/checkout@v4
- run: npm test
deploy:
needs: test
runs-on: ubuntu-latest
permissions:
id-token: write # Solo per OIDC
contents: read
packages: write # Solo per push immagini
environment: production # Richiede approvazione manuale
steps:
- uses: actions/checkout@v4
- name: Deploy
run: ./deploy.sh
Signed Commits
I signed commits garantiscono l'identità del contributor attraverso la firma crittografica GPG o SSH. Senza firma, chiunque può creare un commit con un nome e email arbitrari, impersonando altri developer.
# Configurare GPG per signed commits
gpg --full-generate-key
gpg --list-secret-keys --keyid-format=long
# Configurare Git per firmare automaticamente
git config --global user.signingkey YOUR_KEY_ID
git config --global commit.gpgsign true
git config --global tag.gpgsign true
# Alternativa: firmare con SSH key
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
Deployment Approval Workflows
I deploy in produzione dovrebbero richiedere approvazione esplicita da parte di persone autorizzate. GitHub Environments permette di configurare approvazioni manuali obbligatorie:
# Deploy con approvazione manuale
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging
steps:
- name: Deploy to staging
run: ./deploy.sh staging
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment:
name: production
url: https://myapp.com
# Richiede approvazione da un reviewer designato
steps:
- name: Deploy to production
run: ./deploy.sh production
- name: Notify team
run: |
curl -X POST "






