Nella prima parte abbiamo messo sotto controllo di versione budget, allocazioni, alert e report. Da allora, il provider Terraform di DoiT ha pubblicato cinque minor release in circa due mesi (dalla v1.6 alla v1.10).
Nel frattempo sono cresciuti notevolmente sia il numero di organizzazioni che usano il provider sia il suo traffico API. Le allocazioni rappresentano la maggior parte di quel traffico, e ogni organizzazione che legge i propri budget tramite il provider lo usa anche in scrittura, che si tratti di creare, aggiornare o eliminare budget.
Questo post va quindi in due direzioni:
- Più in profondità sulle risorse principali. Sono i pattern che si scoprono dopo qualche mese di FinOps as code: generare allocazioni, budget e alert da un'unica mappa dei team, health check in fase di plan e report che escono dalla console sotto forma di PDF.
- Più in ampiezza, fino al tenant stesso. Impostazioni a livello di cliente, ruoli personalizzati, onboarding degli utenti e service account con token a rotazione. Alla fine, un report FinOps settimanale girerà in GitHub Actions senza la chiave API personale di nessuno.
Il provider copre ormai 20 risorse e 85 data source. Ogni snippet qui sotto è stato testato su un tenant DoiT reale prima di finire in questo post (applicato, ripianificato per verificare il drift e distrutto ovunque fosse sicuro farlo), e la maggior parte è presente anche negli esempi della documentazione del provider.
Aggiornare da una release v1.x precedente
Se hai configurato tutto dopo il primo post, probabilmente sei sulla v1.5 o su una versione precedente. La maggior parte dei team aggiorna in fretta (la grande maggioranza delle organizzazioni attive è già sulla v1.6 o successiva) e l'upgrade di per sé di solito è indolore. Strada facendo, però, sono stati rimossi alcuni attributi deprecati, e questi sono quelli in cui potresti inciampare:
| Versione | Modifica | Cosa fare |
|---|---|---|
| v1.7 | max_results sui data source di tipo list è un numero |
Rimuovi le virgolette: max_results = 50 |
| v1.8 | doit_budget.scope rimosso |
Usa scopes: un filtro il cui elenco values contiene tutti gli ID delle allocazioni |
| v1.8 | doit_alert.config.attributions rimosso |
Usa config.scopes |
| v1.8 | doit_report.config.metric rimosso |
Usa config.metrics (fino a quattro) |
| v1.8 | Rimosso il componente inverse_selection di doit_allocation |
Usa inverse |
| v1.8 | Layout dei report csv_export / sheets_export rimossi |
Scegli un layout di visualizzazione, ad esempio table |
| v1.8 | request_timeout deve essere superiore a 120s (default 150s) |
Aumenta o rimuovi i valori personalizzati |
| v1.8 | Risorse e data source Insights rimossi | L'API Insights upstream è stata deprecata |
| v1.10 | Gli operatori di limit_by_change usano codici brevi |
gt, gte, lt, lte, b, nb invece di >, >=, … |
| v1.10 | doit_user.job_function rimosso |
Usa job_title |
La guida alla rimozione degli attributi deprecati contiene i dettagli di migrazione per ogni rimozione.
Dalla v1.8, inoltre, ottieni gratis un po' di hardening. I report passano per l'API di esecuzione asincrona: il provider invia la richiesta, esegue il polling e recupera il risultato al posto tuo. Le richieste soggette a rate limiting applicano correttamente il backoff e quelle lente restituiscono l'errore dell'API stessa invece di andare prima in timeout in locale.
Pattern avanzati per le risorse FinOps principali
Allocazioni, budget, alert e report sono le quattro risorse principali della prima parte e rappresentano la maggior parte del traffico API del provider.
Allocazioni su larga scala: una mappa, tutti i team
Se la tua configurazione prevede un'allocazione, un budget e un alert per ogni team, non fare copia e incolla. Definisci invece i tuoi team una volta sola:
locals { teams = { payments = { budget = 12000, label = "payments" } search = { budget = 8000, label = "search" } platform = { budget = 20000, label = "platform" } }}
# Una singola allocazione per team, con il rilevamento delle anomalie attivoresource "doit_allocation" "team" { for_each = local.teams
name = "Team: ${each.key}" description = "All costs labeled owner=${each.value.label}" anomaly_detection = true rule = { formula = "A" components = [{ type = "label" key = "owner" mode = "is" values = [each.value.label] }] }}
# Gli stessi team come un'unica allocazione di gruppo che seleziona le singole qui sopraresource "doit_allocation" "by_team" { name = "Cost by Team" description = "Team allocations combined into one group" unallocated_costs = "Unowned" rules = [for team in doit_allocation.team : { action = "select" id = team.id }]}anomaly_detection è diventato scrivibile sulle allocazioni singole nella v1.7, così il monitoraggio delle anomalie vive nella tua configurazione invece di essere una casella che qualcuno deve ricordarsi di spuntare. L'allocazione di gruppo, inoltre, seleziona le allocazioni dei team invece di ridefinirle.
Suggerimento: costruisci sempre i gruppi con
select. Puoi anche definire le regole di gruppo inline conaction = "create", e l'API DoiT crea dietro le quinte esattamente le stesse allocazioni singole. Ma quelle allocazioni non sono risorse Terraform a sé stanti, quindi le regole inline non possono impostare attributi comeanomaly_detectionofolder_id. Allocazioni singole separate piùselectti danno risorse reali e gestite.
Dato che ora ogni team ha un'allocazione vera con il rilevamento delle anomalie, puoi chiedere quali team stanno generando anomalie e ottenere una spiegazione AI della più costosa:
# Tutte le anomalie (senza max_results, quindi vengono recuperate tutte le pagine),# ordinate in modo che la più costosa venga per primadata "doit_anomalies" "by_cost" { sort_by = "costOfAnomaly" sort_order = "desc"}
locals { # Un'anomalia può appartenere a più allocazioni; va conteggiata sotto ciascuna anomaly_cost_by_allocation = { for name, costs in { for pair in flatten([ for a in data.doit_anomalies.by_cost.anomalies : [ for al in a.allocations : { name = al.name, cost = a.cost_of_anomaly } ] ]) : pair.name => pair.cost... } : name => { anomalies = length(costs), total_cost = sum(costs) } }}
data "doit_anomaly_explanation" "costliest" { count = length(data.doit_anomalies.by_cost.anomalies) > 0 ? 1 : 0 id = data.doit_anomalies.by_cost.anomalies[0].id}
output "costliest_anomaly_explanation" { value = one(data.doit_anomaly_explanation.costliest[*].explanation.text) sensitive = true}L'attributo allocations sulle anomalie (v1.10) elenca ogni allocazione a cui un'anomalia appartiene, e doit_anomaly_explanation (v1.8) restituisce la spiegazione generata insieme ai fatti su cui si basa. Sul nostro tenant di test, l'anomalia principale è risultata "probabilmente causata da un picco nel volume di richieste Amazon SNS Tier 1, in particolare nelle regioni US West 2 e US West 1".
Budget che seguono le allocazioni
Una volta definita la mappa dei team, i budget sono solo un altro for_each. I budget possono inviare notifiche anche su Slack e, dalla v1.8, il provider valida la configurazione Slack prima dell'apply:
resource "doit_budget" "team" { for_each = local.teams
name = "Team: ${each.key}" type = "recurring" time_interval = "month" currency = "USD" amount = each.value.budget start_period = 1767225600000 # 2026-01-01T00:00:00Z in millisecondi
alerts = [{ percentage = 80 }, { percentage = 100 }]
scopes = [{ type = "allocation_rule" id = "allocation_rule" mode = "is" values = [doit_allocation.team[each.key].id] }]
collaborators = [{ email = data.doit_current_user.me.email, role = "owner" }] recipients = [data.doit_current_user.me.email] recipients_slack_channels = [{ id = "C0123456789" customer_id = "your-customer-id" workspace = "your-slack-workspace" }]}Aggiungere un team ora è una modifica di una sola riga a local.teams, e allocazione, budget e (nella prossima sezione) alert seguono automaticamente.
Dalla v1.8, doit_budgets espone anche la classificazione del rischio lato server di DoiT: un risk_status per budget (onTrack, atRisk o unknown), su cui puoi filtrare. Combinalo con un blocco check di Terraform e ogni terraform plan ti dirà quando il budget di un team sta prendendo una brutta piega:
check "team_budgets_on_track" { data "doit_budgets" "team_at_risk" { name_contains = "Team: " filter = "riskStatus:atRisk" }
assert { condition = data.doit_budgets.team_at_risk.row_count == 0 error_message = "Budgets at risk: ${join(", ", [for b in data.doit_budgets.team_at_risk.budgets : b.budget_name])}" }}I blocchi check producono warning, non errori, quindi non bloccano mai un apply, ma chi rivede il plan vede il problema. Per i budget suggeriti dall'AI, il data source doit_budget_suggestions (v1.7) elenca le raccomandazioni in sospeso con il relativo livello di confidenza e l'importo suggerito, così una persona può rivederle in una pull request.
Alert che vale la pena attivare
Nei nostri dati di utilizzo, gli alert sono la meno usata delle quattro risorse principali, e le organizzazioni che gestiscono gli alert con Terraform sono molte meno di quelle che gestiscono i budget. È un divario che vale la pena colmare, perché da luglio gli alert hanno ricevuto due delle aggiunte più pratiche.
Il problema classico degli alert sulla variazione percentuale è il rumore. Un servizio che costa 2 $ al giorno sale a 10 $ e ti arriva un alert "+400%" per otto dollari. ignore_values_range (v1.9) salta ogni valutazione in cui il valore della metrica rientra nei limiti, e recipients_slack_channels invia l'alert là dove il tuo team guarda davvero:
resource "doit_alert" "team_spike" { for_each = local.teams
name = "Team ${each.key}: daily cost spike" config = { metric = { type = "basic", value = "cost" } time_interval = "day" condition = "percentage-change" operator = "gt" value = 30 # percentuale currency = "USD" ignore_values_range = { lower_bound = 0 upper_bound = 50 # USD al giorno } # Valuta ogni servizio separatamente: basta il picco di un solo servizio evaluate_for_each = "fixed:service_description" scopes = [{ type = "label" id = "owner" mode = "is" values = [each.value.label] }] } recipients = [data.doit_current_user.me.email] recipients_slack_channels = [{ id = "C0123456789" shared = true }]}Nota che i limiti sono espressi in unità della metrica (qui, USD al giorno), non in percentuale, e si applicano solo a condition = "percentage-change". Un canale Slack condiviso richiede il suo ID e shared = true; un canale in un workspace collegato richiede invece il suo ID e workspace = "<name>".
Report: Top Movers, previsioni e nuove visualizzazioni
Due novità sui report della v1.6 meritano attenzione.
Top Movers. limit_by_change filtra le righe in base alla variazione da un periodo all'altro, e limit_aggregation controlla come vengono mostrate le righe escluse. Questo report mantiene solo i servizi il cui costo totale supera i 1.000 $ ed è cresciuto del 50% o più:
resource "doit_report" "top_movers" { name = "Top Movers" description = "Services with significant month-over-month growth" config = { metrics = [{ type = "basic", value = "cost" }] aggregation = "total" data_source = "billing" time_interval = "month" dimensions = [{ id = "service_description", type = "fixed" }] time_range = { mode = "last" amount = 3 include_current = true unit = "month" } metric_filter = { metric = { type = "basic", value = "cost" } operator = "gt" values = [1000] operand = "series_total" } limit_by_change = { metric = { type = "basic", value = "cost" } change_type = "percentage" operator = "gte" values = [50] include_incomplete_data = false } limit_aggregation = "top" display_values = "actuals_only" layout = "table" currency = "USD" }}Previsioni e temi. forecast_settings proietta la spesa futura a partire dai dati storici, e i layout della v1.8 (column_and_line_chart, sankey_chart, trend_board e cumulative_comparison) ti offrono più modi per mostrarla. Aggiungi display_settings.theme_id e il report userà i colori del tuo brand:
resource "doit_custom_theme" "brand" { name = "Brand" primary_color = "#1A73E8" colors = { light = ["#1A73E8", "#34A853", "#FBBC04", "#EA4335", "#A142F4", "#24C1E0"] dark = ["#8AB4F8", "#81C995", "#FDD663", "#F28B82", "#C58AF9", "#78D9EC"] }}
resource "doit_report" "forecast" { name = "Spend Forecast" description = "Last 12 months of spend with a 3-month forecast" config = { metrics = [{ type = "basic", value = "cost" }] aggregation = "total" time_interval = "month" currency = "USD" data_source = "billing" time_range = { mode = "last" amount = 12 unit = "month" include_current = true } dimensions = [ { id = "year", type = "datetime" }, { id = "month", type = "datetime" }, ] forecast_settings = { mode = "totals" historical_time_intervals = 12 future_time_intervals = 3 } layout = "column_and_line_chart" display_values = "actuals_only" sort_dimensions = "a_to_z" display_settings = { theme_id = doit_custom_theme.brand.id number_scale = "thousands" } }}Un'avvertenza: i valori di previsione non sono ancora inclusi nei risultati dei report né negli export. Il tema, invece, viene mantenuto fino in fondo, come mostra la prossima sezione.
I report escono dalla console: export in PDF e PNG
Ora puoi ottenere un report da DoiT sotto forma di file, senza che nessuno apra la console. Dalla v1.10, doit_report_result e doit_report_query accettano file_output = "pdf" o "png" e restituiscono un URL di download firmato:
data "doit_report_result" "forecast_pdf" { id = doit_report.forecast.id file_output = "pdf"
lifecycle { postcondition { condition = self.file_output_url != null error_message = "PDF rendering failed. Try applying again." } }}
data "http" "forecast_pdf" { url = data.doit_report_result.forecast_pdf.file_output_url}
resource "local_sensitive_file" "forecast_pdf" { filename = "${path.module}/spend-forecast.pdf" content_base64 = data.http.forecast_pdf.response_body_base64}Il PDF è un documento curato e multipagina con il nome della tua organizzazione nell'intestazione, e il tuo tema personalizzato viene mantenuto: dato che il report di previsione qui sopra imposta display_settings.theme_id, anche il PDF viene disegnato con i colori del tuo brand.
Sostituisci local_sensitive_file con un aws_s3_object (accetta lo stesso content_base64) e il PDF finirà in un bucket. Le esecuzioni dei report passano per l'API di esecuzione asincrona di DoiT, quindi i report pesanti possono richiedere tempo: se necessario, aumenta il timeout di lettura del data source con timeouts = { read = "30m" }.
Non ti serve nemmeno un report salvato. doit_report_query renderizza altrettanto bene una query ad hoc, il che è perfetto per un grafico in un README, in un commento a una pull request o in una pagina wiki:
data "doit_report_query" "top_services_png" { file_output = "png" config = { metrics = [{ type = "basic", value = "cost" }] aggregation = "total" time_interval = "month" currency = "USD" time_range = { mode = "last", amount = 3, unit = "month", include_current = false } dimensions = [ { id = "year", type = "datetime" }, { id = "month", type = "datetime" }, ] # I 5 servizi più costosi group = [{ id = "service_description" type = "fixed" limit = { value = 5, sort = "desc", metric = { type = "basic", value = "cost" } } }] layout = "stacked_column_chart" sort_dimensions = "a_to_z" }}
Suggerimento: imposta
sort_dimensions = "a_to_z"per gli export. Senza, il grafico renderizzato ordina l'asse temporale per valore, quindi settembre può finire prima di agosto. Con questa impostazione, i mesi seguono l'ordine del calendario.
L'URL di download è sensibile e resta valido fino a sette giorni. Ogni plan genera un file nuovo, che è esattamente ciò che serve per un report ricorrente. Lo sfrutteremo nell'esempio finale.
Il tuo tenant come codice
Finora abbiamo parlato solo di dati di costo. Ma una delle funzionalità più adottate del provider è l'onboarding AWS CloudConnect, tramite la risorsa e il modulo del post precedente. È evidente che i team vogliono avere in codice la loro configurazione DoiT, non solo i report, e le ultime tre release coprono il resto del tenant.
Impostazioni a livello di cliente
doit_customer (v1.8) gestisce le impostazioni a livello di organizzazione. Un customer non si crea: si adotta quello che hai già, quindi parti da un import:
import { to = doit_customer.main id = "your-customer-id"}
resource "doit_customer" "main" { url_slug = "my-company"
settings = { currency = "USD" allowed_invite_domains = ["mycompany.com"] mfa_required = true }
contact = { emails = ["finops@mycompany.com"] }}Il tuo primo plan mostra esattamente in cosa le impostazioni attuali differiscono da quanto hai scritto, il che è già di per sé un audit utile. Da quel momento, disattivare l'MFA o consentire un nuovo dominio di invito è una pull request che qualcuno deve approvare, non un interruttore che chiunque può azionare.
Ruoli personalizzati e utenti
doit_role (v1.10) gestisce i ruoli personalizzati. Gli ID dei permessi sono opachi, quindi non digitarli a mano: ricavali dai ruoli predefiniti. Questo ruolo combina due preset in uno:
data "doit_roles" "all" {}
locals { preset_permissions = { for r in data.doit_roles.all.roles : r.name => r.permissions if r.type == "preset" }}
resource "doit_role" "finops_analyst" { name = "FinOps Analyst" description = "View Only plus everything a Finance User can see" permissions = sort(distinct(concat( local.preset_permissions["View Only"], local.preset_permissions["Finance User"], )))}L'onboarding è poi una mappa, proprio come i team di prima:
locals { analysts = { "ana@mycompany.com" = { first_name = "Ana", last_name = "Lopez" } "ravi@mycompany.com" = { first_name = "Ravi", last_name = "Patel" } }}
resource "doit_user" "analyst" { for_each = local.analysts
email = each.key first_name = each.value.first_name last_name = each.value.last_name job_title = "Finance / Accounting" role_id = doit_role.finops_analyst.id}Configurazioni come questa richiedono un'identità con diritti sufficienti a gestire gli utenti. Dalla v1.9, doit_current_user espone i permissions effettivi del chiamante, così puoi far fallire tutto subito con un messaggio chiaro invece di ricevere un 403 a metà apply:
data "doit_current_user" "me" { lifecycle { postcondition { condition = alltrue([for p in ["UsersManager", "ServiceAccountManager"] : contains(self.permissions, p)]) error_message = "The identity running Terraform needs the UsersManager and ServiceAccountManager permissions." } }}Service account e token a rotazione
I service account sono la funzionalità di punta della v1.10. Le pipeline che dialogano con l'API DoiT spesso girano con la chiave API personale di qualcuno, con tutti i permessi di quella persona. Un service account dà all'automazione un'identità propria con i soli permessi di cui ha bisogno, e doit_service_account e doit_service_account_token gestiscono in Terraform sia l'account sia i suoi token.
Ricava il nome e la scadenza del token da una risorsa time_rotating e Terraform genererà un nuovo token ogni volta che la data di rotazione è passata:
resource "doit_service_account" "ci" { name = "ci-pipeline" description = "Runs Terraform from CI" permissions = ["cloudAnalyticsUser", "budgetsReadOnly"]}
resource "time_rotating" "ci_token" { rotation_days = 90}
resource "doit_service_account_token" "ci" { service_account_id = doit_service_account.ci.id name = "ci-${formatdate("YYYYMMDD-hhmmss", time_rotating.ci_token.rfc3339)}" expires_time = timeadd(time_rotating.ci_token.rotation_rfc3339, "168h")
lifecycle { create_before_destroy = true }}Quattro dettagli fanno funzionare il tutto:
- Cambiare
nameoexpires_timesostituisce il token, quindi è il timestamp di rotazione nel nome a innescare la creazione di un nuovo token. Mantiene inoltre i nomi univoci, come devono essere mentre il vecchio e il nuovo token coesistono per un breve periodo. create_before_destroysignifica che il nuovo token esiste prima che il vecchio venga eliminato. Durante i test abbiamo forzato una rotazione: Terraform ha creato il nuovo token, eliminato il vecchio, e il plan successivo era pulito.- La scadenza è una settimana dopo la data di rotazione, così il token continua a funzionare anche se nessuno esegue in tempo il prossimo apply.
access_tokenviene restituito una sola volta, alla creazione. È contrassegnato come sensibile. Passalo dove serve nello stesso apply.
Il token è un normale token API. Impostalo come DOIT_API_TOKEN e il provider (o qualsiasi altro client dell'API DoiT) si autenticherà come service account, vedendo solo i permessi che gli hai assegnato.
Suggerimento: i service account non possono avere più permessi di chi li crea. Richiedere permessi che il chiamante non possiede fallisce con un 403. Nota anche la nomenclatura: i permessi dei service account usano il camelCase (
cloudAnalyticsUser), mentredoit_current_user.permissionsli riporta in PascalCase (CloudAnalyticsUser).
Cloud bill shouldn't be a mystery
One platform for AI and Cloud optimization.
In pillole
Qualche altra novità che vale la pena conoscere:
doit_service_quotasmostra l'utilizzo delle quote AWS e GCP. Abbinalo a un blocco check e ogni plan ti avviserà prima che tu raggiunga un limite:
check "service_quota_headroom" { data "doit_service_quotas" "hot" { min_utilization_percent = 80 }
assert { condition = length(data.doit_service_quotas.hot.items) == 0 error_message = "Quotas at or above 80%: ${join(", ", [for q in data.doit_service_quotas.hot.items : "${q.cloud_provider}/${q.service}/${q.quota} (${q.utilization_percent}%)"])}" } }Sul nostro tenant di test è scattato subito per una quota VPC AWS all'80%. Nota che la lettura delle quote richiede il permesso Manage Settings.
doit_billing_explainerscompone una fattura per payer, inclusi crediti, sconti, risparmi e addebiti marketplace.doit_widget/doit_widgetsespongono i dati dei widget delle dashboard di Cloud Analytics.doit_cloudconnect_supported_featuresmostra quali funzionalità e permessi sono attivi su ciascun account AWS connesso.- I filtri
name_containssudoit_alerts,doit_allocations,doit_budgets,doit_labelsedoit_reportsriducono a una sola riga la domanda "trova tutto ciò che appartiene al team X". - I data source PerfectScale for Commitments (
doit_ps4c_*) e la risorsadoit_support_request_tagscompletano le release.
Mettiamo tutto insieme: un report FinOps settimanale senza chiavi API personali
L'ultimo esempio combina un service account, un token a rotazione, un blocco check, un export PDF e Ava, l'assistente AI di DoiT, in una pipeline GitHub Actions. Gira ogni lunedì e pubblica un riepilogo FinOps con il report completo allegato, usando due piccole configurazioni Terraform:
- Bootstrap, eseguita una volta da un amministratore: crea un service account con permessi minimi, un token a rotazione e il report, poi consegna il token e l'ID del report a GitHub. È lo snippet del service account visto sopra più il report, con due risorse del provider GitHub alla fine:
resource "github_actions_secret" "doit_api_token" { repository = "doit-finops-demo" secret_name = "DOIT_API_TOKEN" plaintext_value = doit_service_account_token.reporting.access_token }
resource "github_actions_variable" "report_id" { repository = "doit-finops-demo" variable_name = "DOIT_REPORT_ID" value = doit_report.weekly.id }Rieseguire il bootstrap dopo la data di rotazione genera un nuovo token e aggiorna il secret nello stesso apply, così la pipeline non se ne accorge nemmeno.
- Reporting, eseguita dalla pipeline: un blocco check sui budget, l'export PDF visto prima e una domanda per Ava. Non contiene risorse a parte il file scaricato, quindi non ha bisogno di uno state remoto:
data "doit_ava" "summary" { question = "Summarize report ${var.report_id} in three short bullet points for an engineering audience. Mention the biggest week-over-week change." }
output "summary" { value = <<-EOT ## Weekly FinOps report
${data.doit_ava.summary.answer}
_The full report is attached to this run as `weekly-cost-report`._ EOT }Il workflow in sé è breve:
name: Weekly FinOps report
on: schedule: - cron: "0 7 * * 1" # lunedì alle 07:00 UTC workflow_dispatch:
jobs: report: runs-on: ubuntu-latest defaults: run: working-directory: reporting env: DOIT_API_TOKEN: ${{ secrets.DOIT_API_TOKEN }} TF_VAR_report_id: ${{ vars.DOIT_REPORT_ID }} steps: - uses: actions/checkout@v7 - uses: hashicorp/setup-terraform@v4 with: terraform_wrapper: false - run: terraform init -input=false - run: terraform apply -auto-approve -input=false - run: terraform output -raw summary >> "$GITHUB_STEP_SUMMARY" - uses: actions/upload-artifact@v7 with: name: weekly-cost-report path: reporting/weekly-cost-report.pdfEcco un'esecuzione reale. Il blocco check ha segnalato nel log un budget a rischio, il riepilogo di Ava compare nella pagina della run e il PDF è allegato come artifact:


Guarda il terzo punto del riepilogo di Ava e poi il grafico: il balzo di Cloud SQL nella settimana del 7 settembre è esattamente il picco viola della settimana 37. Il riepilogo di Ava è generato dall'AI, quindi la formulazione cambia da una run all'altra, ma è un utile primo paragrafo per un lunedì mattina.
Cosa abbiamo imparato costruendo tutto questo:
- Mantieni minimi i permessi del robot. Il service account della pipeline ha solo due permessi:
cloudAnalyticsUserebudgetsReadOnly. È anche il motivo per cui il check sulle quote resta fuori da questa pipeline: richiederebbe Manage Settings. - Il robot vede solo i budget pubblici. I service account non hanno un indirizzo email, quindi non puoi aggiungerne uno come collaboratore di un budget. I budget che la pipeline deve controllare richiedono
public = "viewer"o superiore suldoit_budget. - Nessuno copia un token a mano. Il token passa dall'API DoiT direttamente al secret GitHub all'interno di un unico apply. L'unica altra copia è lo state Terraform del bootstrap, quindi conserva quello state in un posto sicuro.
Per concludere
Ricapitolando:
- Le risorse principali hanno guadagnato profondità: genera allocazioni, budget e alert da un'unica mappa, costruisci allocazioni di gruppo con
selecte lascia che i blocchi check esaminino i tuoi budget a ogni plan. - I report escono dalla console: renderizza report salvati e query ad hoc come PDF e PNG, con il tuo tema.
- Il tuo tenant ora è codice: impostazioni, ruoli, utenti e service account con token a rotazione, così le tue pipeline non prendono più in prestito la chiave API di una persona.
I prossimi passi:
- Aggiorna alla v1.10 con l'aiuto della tabella all'inizio di questo post.
- Parti dalla mappa dei team. Riunisce allocazioni, budget e alert in un'unica configurazione.
- Sposta le tue pipeline dalle chiavi API personali a un service account con token a rotazione.
- Segui le release del repository (Watch → Custom → Releases). Il provider supporta tutto ciò che l'API DoiT offre, quindi le nuove funzionalità dell'API compaiono lì man mano che vengono aggiunte.
Il provider è open source su github.com/doitintl/terraform-provider-doit, e la documentazione contiene la maggior parte degli esempi di questo post, e molti altri. Se qualcosa manca o risulta macchinoso, apri una issue e faccelo sapere.