Quick Start
Prerequisiti
- Node.js 20+ — verifica con
node --version - Credenziali AWS con permessi in sola lettura (vedi Permessi IAM sotto)
Installazione
npm install -g @cloudrift/cli
# oppure eseguilo una tantum, senza installarlo:
npx @cloudrift/cli analyze
macOS/Linux via Homebrew:
brew install elleVas/cloudrift/cloudrift
Dai sorgenti (per contribuire, o per eseguire modifiche non ancora rilasciate):
git clone https://github.com/elleVas/cloudrift.git
cd cloudrift
pnpm install
pnpm nx build cli # output compilato in apps/cli/dist/
Gli esempi qui sotto usano il comando cloudrift (installazione da npm). Esegui dai sorgenti? Sostituisci cloudrift con node apps/cli/dist/main.js.
Configurazione credenziali AWS
cloudrift usa la chain standard di credenziali AWS SDK v3. Tre opzioni, in ordine di preferenza:
Opzione A — AWS CLI (consigliato)
aws configure
# inserisci: Access Key ID, Secret Access Key, regione default (es. us-east-1), output format (json)
Questo crea ~/.aws/credentials con il profilo default.
Opzione B — File ~/.aws/credentials manuale
[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Opzione C — Variabili d’ambiente
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
export AWS_DEFAULT_REGION=us-east-1
Verifica: aws sts get-caller-identity deve restituire il tuo account ID senza errori.
Permessi IAM necessari
L’utente/ruolo AWS deve avere questa policy in sola lettura:
{
"Effect": "Allow",
"Action": [
"ec2:DescribeVolumes",
"ec2:DescribeAddresses",
"ec2:DescribeInstances",
"ec2:DescribeSnapshots",
"ec2:DescribeImages",
"ec2:DescribeNatGateways",
"ec2:DescribeNetworkInterfaces",
"ec2:DescribeLaunchTemplates",
"ec2:DescribeLaunchTemplateVersions",
"cloudwatch:GetMetricStatistics",
"rds:DescribeDBInstances",
"rds:DescribeDBClusters",
"rds:DescribeDBSnapshots",
"elasticloadbalancing:DescribeLoadBalancers",
"elasticloadbalancing:DescribeTargetGroups",
"elasticloadbalancing:DescribeTargetHealth",
"logs:DescribeLogGroups",
"s3:ListAllMyBuckets",
"s3:GetBucketLifecycleConfiguration",
"s3:ListMultipartUploadParts",
"s3:ListBucketMultipartUploads",
"ecr:DescribeRepositories",
"ecr:DescribeImages",
"codepipeline:ListPipelines",
"codepipeline:ListPipelineExecutions",
"secretsmanager:ListSecrets",
"lambda:ListFunctions",
"elasticfilesystem:DescribeFileSystems",
"dynamodb:ListTables",
"dynamodb:DescribeTable",
"elasticache:DescribeCacheClusters",
"sagemaker:ListNotebookInstances",
"sagemaker:ListEndpoints",
"sagemaker:DescribeEndpoint",
"sagemaker:DescribeEndpointConfig",
"sagemaker:ListEndpointConfigs",
"sagemaker:ListModels",
"sagemaker:DescribeModel",
"sagemaker:ListTags",
"sqs:ListQueues",
"sqs:GetQueueAttributes",
"sqs:ListDeadLetterSourceQueues",
"sqs:ListQueueTags",
"tag:GetResources",
"eks:ListClusters",
"eks:ListNodegroups",
"eks:DescribeNodegroup",
"sts:GetCallerIdentity"
],
"Resource": "*"
}
--live-pricingrichiede in piùpricing:GetProducts(AWS Pricing API). Non serve per il pricing statico di default.
Primo utilizzo
# Scansione della regione di default (us-east-1)
# L'account ID viene rilevato automaticamente via STS
cloudrift analyze
# Scansione di più regioni
cloudrift analyze -r us-east-1 eu-west-1 ap-southeast-1
# Solo servizi specifici (salta il picker interattivo)
cloudrift analyze --scanners ebs-volume elastic-ip
# Tutti gli scanner senza picker interattivo
cloudrift analyze --all-services
# Disattiva il periodo di grazia (segnala risorse di qualsiasi età)
cloudrift analyze --min-age-days 0
Il picker interattivo
Lanciando analyze in un vero terminale (fuori da CI), appare un picker interattivo — una checklist di tutti gli scanner, tutti pre-selezionati. Premi Invio per scansionare tutto, oppure deseleziona quelli che non ti servono.
Il picker non appare mai quando:
stdoutnon è un TTY (piped output)- La variabile
CI=trueè settata - Usi
--silent,--scanners <kinds...>o--all-services
In questi casi tutti gli scanner vengono eseguiti automaticamente.
Formati di output
# Tabella console (default)
cloudrift analyze
# Output JSON (machine-readable, ideale per piping)
cloudrift analyze --format json | jq '.totalWasteMonthlyUsd'
# Filtra findings con jq
cloudrift analyze --format json | jq '.findings[] | select(.category=="waste")'
# Markdown per GitHub Actions step summary
cloudrift analyze --format markdown >> "$GITHUB_STEP_SUMMARY"
Nei formati machine-readable (
json,markdown) tutti i messaggi umani vanno su stderr, così su stdout resta solo il report — ideale per il piping.
Report PDF
# PDF con nome automatico (cloudrift-reports/AWS_report_YYYY_MM_DD.pdf)
cloudrift analyze --pdf
# PDF con nome personalizzato, nessun output a terminale
cloudrift analyze --pdf ./report.pdf --silent
Il report PDF contiene:
- Executive summary — totale mensile e annuale, numero risorse, breakdown per tipo
- Top raccomandazioni — fino a 8 voci ordinate per impatto, con risparmio annuale
- Pagine di dettaglio — una tabella per ogni tipo di risorsa trovata
- Scan warnings — elencati se alcuni tipi non hanno potuto essere scansionati
Ordine dei flag: il filename di
--pdf=./report.pdf --silentper evitare ambiguità di ordine.
Report JSON su file
# Scrive anche un file JSON su disco (indipendente da --format)
cloudrift analyze --json
# Con nome personalizzato
cloudrift analyze --json ./report.json --silent
Gestione errori parziali
Se la scansione di un tipo di risorsa fallisce (es. permessi mancanti su CloudWatch per i NAT Gateway), il tool:
- Restituisce comunque tutti gli altri risultati
- Mostra una sezione “Scan Warnings” con i dettagli dell’errore
- Indica il totale come
(incomplete — see warnings above)
⚠ Scan Warnings
• NAT Gateways: Access denied to CloudWatch metrics
Total estimated waste: $56.20/month (incomplete — see warnings above)
L’exit code resta guidato solo dalla soglia di costo, mai dagli errori di scansione.
Tutte le opzioni
| Flag | Descrizione | Default |
|---|---|---|
-r, --regions <regioni...> |
Regioni AWS da scansionare | us-east-1 |
--format <format> |
Formato stdout: table, json, markdown |
table |
--config <path> |
Percorso del file di config | auto-rilevato |
--live-pricing |
Prezzi correnti dall’AWS Pricing API | off |
--scanners <kinds...> |
Solo questi servizi (salta picker) | — |
--all-services |
Tutti gli scanner senza picker | on in CI/non-TTY |
--account-id <id> |
Override account ID (auto-rilevato via STS) | auto |
--assume-role-arn <arn> |
Assume questo ruolo IAM per accesso cross-account | — |
--external-id <id> |
External ID per --assume-role-arn |
— |
--min-age-days <giorni> |
Periodo di grazia in giorni | 7 |
--ignore-tag <tag> |
Tag di esclusione | cloudrift:ignore |
--pdf [filename] |
Genera report PDF | — |
--json [filename] |
Genera report JSON su disco | — |
--silent |
Nessun output su stdout | off |
--notify-slack |
Notifica Slack se lo spreco supera costAlertThresholdUsd (legge SLACK_WEBHOOK_URL dall’env) |
off |
--notify-webhook |
POST di un riepilogo JSON a un webhook (legge CLOUDRIFT_WEBHOOK_URL dall’env) |
off |
--notify-email <indirizzo> |
Email con un riepilogo (legge CLOUDRIFT_SMTP_* dall’env) |
off |
-h, --help |
Mostra l’help | — |
Notifiche: disponibili anche su
dead-resources,resource-securityehistory --compare(condizioni di trigger diverse — vedi ciascun comando sotto). Best-effort: un webhook rotto o un SMTP mal configurato loggano un warning e non fanno fallire lo scan. Ogni credenziale viene letta dall’ambiente, mai da un flag — impostale nel profilo della shell o come secret di CI, mai in un file committato.
Scansione cross-account
cloudrift può scansionare un account diverso da quello a cui appartengono le tue credenziali, assumendo un ruolo IAM via STS:
# Scansiona un account diverso assumendo un ruolo al suo interno
cloudrift analyze --assume-role-arn arn:aws:iam::222222222222:role/cloudrift-scanner
# Con external ID (se la trust policy lo richiede)
cloudrift analyze --assume-role-arn arn:aws:iam::222222222222:role/cloudrift-scanner --external-id il-mio-secret
# Scansiona più account da un loop di shell
for account in 111111111111 222222222222; do
cloudrift analyze \
--assume-role-arn "arn:aws:iam::${account}:role/cloudrift-scanner" \
--format json > "report-${account}.json"
done
Tutti i comandi (analyze, cost, trend, dead-resources, resource-security) accettano --assume-role-arn e --external-id.
Comandi cost e trend
Oltre alla waste detection, cloudrift offre due comandi per confrontare e tracciare la spesa AWS via Cost Explorer:
# Confronta spesa di questo mese con gli stessi giorni del mese scorso
cloudrift cost
# Trend mensile degli ultimi 12 mesi
cloudrift trend --months 12
# Solo EC2 e S3, salta la conferma di fatturazione
cloudrift trend --months 12 --services ec2 s3 --yes
# Fallisce in CI se la spesa è aumentata più del 20%
cloudrift cost --fail-on-increase 20 --format json
⚠️
costetrendchiamano AWS Cost Explorer, che fattura $0.01 a richiesta — gli unici comandi di cloudrift che possono generare un costo AWS. Entrambi chiedono conferma interattiva prima della prima chiamata (saltabile con-y/--yes,--silent, o in CI). I periodi chiusi vengono cachati su disco.
Comando dead-resources
Trova risorse lasciate morte o inutilizzate nell’account con costo AWS diretto pari a $0 (invisibili alla waste detection): key pair EC2 inutilizzate, security group orfani, utenti/ruoli IAM inattivi, access key non ruotate, e altro — 18 check in totale.
# Tutti i check, regione di default
cloudrift dead-resources
# Più regioni
cloudrift dead-resources -r us-east-1 eu-west-1
# Solo i check IAM
cloudrift dead-resources --scanners iam-user-inactive iam-policy-unattached
# Output machine-readable
cloudrift dead-resources --format json | jq '.findings[] | select(.severity=="warning")'
# Report PDF
cloudrift dead-resources --pdf ./hygiene.pdf --silent
I finding portano una severity (info / warning / critical) invece di una stima $/mese. Richiede permessi IAM aggiuntivi — vedi la policy completa con cloudrift iam-policy.
Comando resource-security
Scansiona la postura di sicurezza dell’account: MFA disabilitata, access key non ruotate, security group aperti su internet, bucket S3 pubblici, EBS/RDS non cifrati, GuardDuty/Config/Security Hub non abilitati, VPC Flow Logs disabilitati, rotazione delle chiavi KMS, policy IAM admin wildcard, certificati ACM in scadenza, resource policy pubbliche su Lambda/SNS/SQS/ECR/Secrets Manager, e altro — 29 check in totale.
# Ogni check, regione di default
cloudrift resource-security
# Solo i check IAM
cloudrift resource-security --scanners iam-root-mfa-disabled iam-user-mfa-disabled
# Output machine-readable
cloudrift resource-security --format json | jq '.findings[] | select(.severity=="critical")'
# Report PDF
cloudrift resource-security --pdf ./sicurezza.pdf --silent
Anche qui i finding portano una severity. Richiede permessi IAM aggiuntivi — vedi la policy completa con cloudrift iam-policy.
Comando history
Visualizza lo storico locale delle scansioni. Ogni esecuzione di analyze, dead-resources e resource-security salva un snapshot in un file SQLite locale (~/.cloudrift/trends/<account-id>.db) — in modalità best-effort, senza mai bloccare la scansione.
# Tutti gli snapshot registrati, dal più recente
cloudrift history
# Solo lo storico cost-waste, ultime 10 esecuzioni
cloudrift history --domain cloud-cost --limit 10
# Output machine-readable
cloudrift history --format json | jq '.[0].payload'
# Report HTML autocontenuto (grafici per dominio, stat tiles, previsione lineare)
cloudrift history --html
# Report HTML per un singolo dominio
cloudrift history --domain cloud-cost --html
# Confronta due snapshot specifici
cloudrift history --compare
Il report --html cambia in base al dominio: cloud-cost mostra una linea di spreco in dollari con previsione lineare e una lista “top resource type per spreco”; dead-resources/resource-security mostrano critical/warning/info come tre linee separate. Il report combinato apre con 3 stat tile esecutivi pensati per un pubblico CTO/CEO.
Nessun dato viene mai caricato da nessuna parte: il file non lascia mai la tua macchina.
Comando iam-policy
Stampa la policy IAM read-only completa richiesta da cloudrift come JSON pronto da incollare:
cloudrift iam-policy
Nessuna chiamata AWS, utile per copiarla direttamente nella console IAM, in Terraform o CDK.
Output di esempio
Scanning us-east-1 (account 123456789012) for wasted cloud resources...
EBS Volumes — Unattached
┌────────────────────┬───────────┬────────┬──────┬────────────┬────────────┐
│ Volume ID │ Region │ Size │ Type │ Created │ Est. Cost │
├────────────────────┼───────────┼────────┼──────┼────────────┼────────────┤
│ vol-0abc123def456 │ us-east-1 │ 500 GB │ gp3 │ 2025-01-15 │ $40.00/mo │
└────────────────────┴───────────┴────────┴──────┴────────────┴────────────┘
Total estimated waste: $40.00/month
Prezzi per regione
I prezzi sono region-aware. Regioni con listino specifico: us-east-1, us-west-2, eu-west-1, eu-central-1, ap-southeast-1, ap-northeast-1. Le altre usano il fallback di us-east-1.
Ogni report mostra prices as of con la data di ultima verifica del listino.