Introduzione: perchè la Gestione dei Segreti e Critica
Una singola API key esposta in un repository pubblico può costare migliaia di euro in pochi minuti. Bot automatizzati scandagliano costantemente GitHub alla ricerca di credenziali committate per errore: chiavi AWS, token Firebase, password di database. La gestione dei segreti non e un optional nella pipeline CI/CD, e una necessità assoluta.
In questo articolo esploreremo in profondità come gestire i segreti in modo sicuro nelle pipeline CI/CD, partendo da GitHub Secrets fino ad arrivare a soluzioni enterprise come HashiCorp Vault. Ogni strategia viene illustrata con esempi pratici specifici per applicazioni Angular.
Cosa Imparerai in Questo Articolo
- perchè la gestione dei segreti e fondamentale per la sicurezza
- Come funzionano GitHub Secrets (repository, environment, organization)
- La differenza tra variabili d'ambiente e segreti
- Come gestire la sicurezza dei file
.env - La differenza tra segreti runtime e build-time
- Strategie di rotazione dei segreti
- Soluzioni vault: HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager
- Come prevenire il leak di segreti con git-secrets e pre-commit hook
- Best practice per audit trail e compliance
1. GitHub Secrets: La Base della Gestione Segreti
GitHub offre tre livelli di segreti, ognuno con un ambito di visibilità diverso. Comprendere quando usare ciascun livello e fondamentale per una gestione efficace.
Livelli di GitHub Secrets
| Livello | Ambito | Caso d'Uso | Chi Può Accedere |
|---|---|---|---|
| Repository | Singolo repository | API key specifiche del progetto | Tutti i workflow del repo |
| Environment | Ambiente specifico (staging, production) | Credenziali di produzione | Solo workflow con environment specificato |
| Organization | Tutti i repository dell'organizzazione | Token condivisi (npm, Docker Hub) | Repository selezionati dall'admin |
Configurare i Segreti nel Repository
Per aggiungere un segreto al repository, vai su Settings > Secrets and variables > Actions > New repository secret. Ecco come usarli nei workflow:
# Accedere ai segreti del repository
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy to Firebase
env:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
run: firebase deploy --token "$FIREBASE_TOKEN"
# I segreti vengono automaticamente mascherati nei log
- name: Debug (il segreto viene mostrato come ***)
run: echo "Token is ${{ secrets.FIREBASE_TOKEN }}"
Segreti per Ambiente
I segreti per ambiente sono la scelta migliore per separare le credenziali di staging e
produzione. Richiedono la keyword environment nel job:
# Segreti per ambiente
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging
steps:
- name: Deploy to staging
env:
# Usa il segreto dell'ambiente "staging"
API_KEY: ${{ secrets.API_KEY }}
DEPLOY_URL: ${{ vars.DEPLOY_URL }}
run: |
echo "Deploying to $DEPLOY_URL"
firebase deploy --token "${{ secrets.FIREBASE_TOKEN }}"
deploy-production:
runs-on: ubuntu-latest
environment: production
needs: deploy-staging
steps:
- name: Deploy to production
env:
# Usa il segreto dell'ambiente "production" (diverso!)
API_KEY: ${{ secrets.API_KEY }}
run: firebase deploy --token "${{ secrets.FIREBASE_TOKEN }}"
Protezione degli Ambienti di Produzione
Configura sempre le Environment Protection Rules per l'ambiente production:
richiedi l'approvazione manuale di un reviewer prima del deploy, limita i branch che possono
deployare a production (solo main), e abilita il timer di attesa per avere un
buffer di sicurezza.
2. Variabili d'Ambiente vs Segreti
E importante distinguere tra variabili d'ambiente e segreti. GitHub Actions supporta entrambi ma con caratteristiche diverse:
Variabili vs Segreti
| Caratteristica | Variables (vars) |
Secrets (secrets) |
|---|---|---|
| Visibilità nei log | Visibili in chiaro | Mascherati con *** |
| Crittografia | No | Si (Libsodium sealed box) |
| Leggibili dopo la creazione | Si | No (solo sovrascrivibili) |
| Uso tipico | URL, nomi ambiente, feature flags | Token, password, chiavi API |
# Esempio: variabili vs segreti
jobs:
build:
runs-on: ubuntu-latest
environment: production
env:
# Variabili: configurazione non sensibile
API_URL: ${{ vars.API_URL }}
APP_NAME: ${{ vars.APP_NAME }}
ENABLE_ANALYTICS: ${{ vars.ENABLE_ANALYTICS }}
steps:
- uses: actions/checkout@v4
- name: Build with environment config
env:
# Segreti: informazioni sensibili
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
ANALYTICS_KEY: ${{ secrets.ANALYTICS_KEY }}
run: |
echo "Building for $API_URL"
npm run build -- --configuration=production
3. Sicurezza dei File .env
I file .env sono comodi per lo sviluppo locale ma rappresentano un rischio
significativo se gestiti male. Ecco le regole fondamentali:
Struttura Raccomandata
# Struttura dei file .env nel progetto
project/
.env # MAI committato (in .gitignore)
.env.example # Template SENZA valori reali (committato)
.env.development # Valori di sviluppo (opzionale, in .gitignore)
.env.production # MAI committato, MAI nel repository
# .env.example - Template committato nel repository
# Copiare in .env e compilare con i valori reali
API_URL=https://api.example.com
FIREBASE_PROJECT_ID=your-project-id
ANALYTICS_ID=
SECRET_KEY=
# .env - File locale (DEVE essere in .gitignore)
API_URL=https://api.example.com
FIREBASE_PROJECT_ID=my-actual-project
ANALYTICS_ID=G-XXXXXXXXXX
SECRET_KEY=super-secret-value-123
Regola d'Oro per .gitignore
# .gitignore - Escludere SEMPRE i file .env
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
.env.production
# Ma NON escludere il template
!.env.example
4. Segreti Runtime vs Build-Time
Per le applicazioni Angular, e cruciale capire la differenza tra segreti disponibili al momento della build e segreti disponibili a runtime. Angular e un framework frontend: tutto ciò che viene incluso nel bundle e visibile nel browser.
Regola Fondamentale per il Frontend
Mai includere segreti nel bundle frontend. Qualsiasi valore presente nei file
environment.ts di Angular e visibile a chiunque apra gli strumenti sviluppatore
del browser. Le API key pubbliche (come Google Maps o Google Analytics) sono accettabili,
ma token privati, chiavi di crittografia e password non devono mai essere nel codice frontend.
// environment.ts - Cosa e sicuro e cosa NO
// SICURO: chiavi pubbliche con restrizioni di dominio
export const environment = {
production: true,
apiUrl: 'https://api.example.com',
googleMapsKey: 'AIza...', // OK: limitata per dominio nella console Google
analyticsId: 'G-XXXXX', // OK: e un identificatore pubblico
sentryDsn: 'https://xxx@sentry.io/123', // OK: limitata per dominio
};
// MAI FARE QUESTO:
// firebaseAdminKey: 'xxxxx', // PERICOLOSO: accesso admin completo
// stripeSecretKey: 'sk_xxxxx', // PERICOLOSO: accesso ai pagamenti
// dbPassword: 'password123', // PERICOLOSO: accesso al database
Gestire Build-Time Secrets nella Pipeline
# Iniettare valori sicuri al build time
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
# Sostituire i placeholder nell'environment file
- name: Configure environment
run: |
cat > src/environments/environment.prod.ts << 'ENVEOF'
export const environment = {
production: true,
apiUrl: '${{ vars.API_URL }}',
analyticsId: '${{ vars.ANALYTICS_ID }}',
};
ENVEOF
- run: npm ci
- run: npx ng build --configuration=production
5. Rotazione dei Segreti
La rotazione periodica dei segreti e una pratica di sicurezza fondamentale. Anche se un segreto non e stato compromesso, la rotazione riduce la finestra di esposizione in caso di leak non rilevato.
Piano di Rotazione Consigliato
| Tipo di Segreto | Frequenza | Motivo |
|---|---|---|
| Token di deploy (Firebase, Vercel) | Ogni 90 giorni | Accesso alle risorse di produzione |
| API key di servizi terzi | Ogni 180 giorni | Rischio di compromissione nel tempo |
| Token npm/Docker Hub | Ogni 90 giorni | Accesso alla pubblicazione di pacchetti |
| Service Account JSON | Ogni 365 giorni | Credenziali di lungo termine |
| Segreto compromesso | Immediatamente | Emergenza di sicurezza |
# Workflow per promemoria di rotazione
name: Secret Rotation Reminder
on:
schedule:
- cron: '0 9 1 */3 *' # Primo giorno di ogni trimestre
jobs:
remind:
runs-on: ubuntu-latest
steps:
- name: Check secret age
run: |
echo "Reminder: E il momento di ruotare i segreti del repository."
echo "Segreti da controllare:"
echo "- FIREBASE_SERVICE_ACCOUNT"
echo "- NPM_TOKEN"
echo "- DOCKER_HUB_TOKEN"
echo "Vai su Settings > Secrets per aggiornare i valori."
- name: Create GitHub Issue
uses: actions/github-script@v7
with:
script: |
github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'Rotazione trimestrale dei segreti',
body: 'E il momento di ruotare i segreti CI/CD.',
labels: ['security', 'maintenance']
});
6. Soluzioni Vault Enterprise
Per organizzazioni con requisiti di sicurezza avanzati, GitHub Secrets potrebbe non essere sufficiente. Le soluzioni vault offrono funzionalità aggiuntive come audit dettagliato, rotazione automatica e crittografia avanzata.
HashiCorp Vault
# Integrare HashiCorp Vault con GitHub Actions
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Import Secrets from Vault
uses: hashicorp/vault-action@v3
with:
url: https://vault.example.com
method: jwt
role: github-actions
secrets: |
secret/data/production/firebase token | FIREBASE_TOKEN ;
secret/data/production/api key | API_KEY ;
- name: Use imported secrets
run: |
echo "Firebase token is available as env var"
firebase deploy --token "$FIREBASE_TOKEN"
Confronto Soluzioni Vault
Vault Solutions a Confronto
| Caratteristica | GitHub Secrets | HashiCorp Vault | AWS Secrets Manager | GCP Secret Manager |
|---|---|---|---|---|
| Costo | Gratuito | Self-hosted o Cloud | Pay-per-use | Pay-per-use |
| Rotazione automatica | No | Si | Si | Si |
| Audit log | Limitato | Completo | CloudTrail | Cloud Audit |
| Complessità | Bassa | Alta | Media | Media |
| Ideale per | Piccoli team | Enterprise | Ecosistema AWS | Ecosistema GCP |
7. Prevenire il Leak di Segreti
La prevenzione e più efficace della cura. Ecco gli strumenti e le pratiche per impedire che i segreti finiscano nel repository.
git-secrets: Scansione Pre-Commit
# Installare git-secrets
# macOS
brew install git-secrets
# Linux
git clone https://github.com/awslabs/git-secrets.git
cd git-secrets && make install
# Configurare nel repository
cd my-project
git secrets --install
git secrets --register-aws
# Aggiungere pattern personalizzati
git secrets --add 'FIREBASE_TOKEN[=:]\s*[A-Za-z0-9]+'
git secrets --add 'sk_live_[A-Za-z0-9]+'
git secrets --add 'AIza[0-9A-Za-z\\-_]{35}'
# Scansionare il repository esistente
git secrets --scan
Pre-Commit Hook con Husky
# Installare husky
npm install -D husky
npx husky init
# Creare il pre-commit hook
cat > .husky/pre-commit << 'HOOKEOF'
#!/bin/sh
# Controllare che nessun segreto venga committato
echo "Checking for secrets..."
# Pattern comuni di segreti
PATTERNS=(
'AKIA[0-9A-Z]{16}' # AWS Access Key
'sk_live_[a-zA-Z0-9]+' # Stripe Secret Key
'AIza[0-9A-Za-z\-_]{35}' # Google API Key
'ghp_[a-zA-Z0-9]{36}' # GitHub Personal Token
'xox[bpoas]-[a-zA-Z0-9-]+' # Slack Token
)
for pattern in "${PATTERNS[@]}"; do
if git diff --cached --name-only -z | xargs -0 grep -lP "$pattern" 2>/dev/null; then
echo "ERRORE: Possibile segreto rilevato!"
echo "Pattern: $pattern"
exit 1
fi
done
echo "Nessun segreto rilevato."
HOOKEOF
chmod +x .husky/pre-commit
GitHub Secret Scanning
GitHub offre anche una funzionalità integrata di Secret Scanning che rileva automaticamente pattern noti di segreti nei commit push. Per i repository pubblici e attiva di default; per i repository privati, e disponibile con GitHub Advanced Security.
8. Audit Trail e Compliance
Per organizzazioni con requisiti di compliance (SOC 2, GDPR, ISO 27001), e necessario mantenere un registro di chi accede ai segreti e quando:
# Workflow con logging dettagliato
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- name: Log deployment attempt
run: |
echo "=== DEPLOYMENT AUDIT LOG ==="
echo "Timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo "Actor: ${{ github.actor }}"
echo "Ref: ${{ github.ref }}"
echo "SHA: ${{ github.sha }}"
echo "Workflow: ${{ github.workflow }}"
echo "Run ID: ${{ github.run_id }}"
echo "Environment: production"
echo "==========================="
- name: Deploy
run: firebase deploy --token "${{ secrets.FIREBASE_TOKEN }}"
- name: Log deployment result
if: always()
run: |
echo "Deploy status: ${{ job.status }}"
Checklist Sicurezza dei Segreti
- Tutti i file
.envsono nel.gitignore - Esiste un file
.env.examplesenza valori reali - I segreti di produzione usano GitHub Environment Secrets
- L'ambiente production ha le protection rules attive
- I pre-commit hook controllano i pattern di segreti
- La rotazione dei segreti e pianificata trimestralmente
- Il team sa cosa fare in caso di leak (procedura di emergenza)
- Nessun segreto privato e presente nel codice frontend
Conclusione
La gestione dei segreti e un aspetto della sicurezza che non si può trascurare. In questo articolo abbiamo esplorato l'intero spettro delle soluzioni: da GitHub Secrets per i piccoli team, ai vault enterprise per le organizzazioni con requisiti di compliance avanzati.
I principi fondamentali da ricordare sono: mai committare segreti nel repository, usare livelli di ambiente per separare staging e produzione, implementare pre-commit hook per la prevenzione, pianificare la rotazione regolare dei segreti, e tenere sempre una procedura di emergenza pronta in caso di leak.
Nel prossimo articolo ci concentreremo sulle performance: configureremo performance budgets e Lighthouse CI nella pipeline per garantire che ogni deploy mantenga standard di qualità elevati.
Domande frequenti
Qual è il rischio più grande se una API key viene esposta in un repository pubblico?
Il rischio più grande è quello di essere scoperti e utilizzati da bot automatizzati, che possono causare danni significativi in pochi minuti.
Come si configurano i segreti nel repository su GitHub?
Per aggiungere un segreto al repository, vai su Settings > Secrets and variables > Actions > New repository secret.
Qual è la differenza tra variabili d'ambiente e segreti in GitHub Actions?
Le variabili d'ambiente sono visibili a tutti i job di una pipeline, mentre i segreti sono accessibili solo ai job specificati con la keyword "secrets".
Perché è importante non includere segreti nel bundle frontend delle applicazioni Angular?
Perché tutto ciò che viene incluso nel bundle è visibile nel browser degli utenti e rappresenta un rischio significativo per la sicurezza.

Commenti
Caricamento commenti...
Accedi per commentare