Skip to content

ydah/terratally

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TerraTally

TerraTally is a post-apply FinOps tool that attributes actual cloud billing costs back to Terraform resources, modules, workspaces, repositories, pull requests, and owners.

It joins Terraform state identities, apply events, Git metadata, and billing exports into a cost ledger. The default storage is a local JSON ledger, with PostgreSQL schema and SQL export support for production use.

Features

  • Terraform state pull and terraform show -json identity extraction.
  • Secret-safe state handling through allowlisted identity/tag fields.
  • AWS CUR CSV import, Athena query generation, and Athena query-result import.
  • Azure Cost Management CSV and Google Cloud Billing CSV import.
  • Direct ARN/ID/bucket/name matching, Terraform tag matching, ambiguous split, shared-cost allocation, and unmatched buckets.
  • Attribution confidence scoring.
  • Apply event ingestion from CLI, Terraform plan JSON, GitHub Actions, Atlantis, and HCP Terraform-style payloads.
  • Ownership resolution from tags, config rules, CODEOWNERS, PR author mapping, git last author, workspace defaults, and unknown.
  • JSON, CSV, and Markdown reports for resources, modules, owners, unmatched costs, tag remediation, metrics, and PR deltas.
  • REST API and a compact dashboard at /dashboard.
  • GitHub PR comment and Slack webhook notification adapters with dry-run support.
  • PostgreSQL schema, views, and SQL export/push support.

Requirements

  • Go 1.26 or newer.
  • Optional: AWS CLI for live Athena imports.
  • Optional: psql for pushing exported SQL to PostgreSQL.
  • Optional: GITHUB_TOKEN, SLACK_WEBHOOK_URL, DATABASE_URL, and TERRATALLY_API_TOKEN for integrations.

The implementation uses only the Go standard library.

Quick Start

Run tests:

go test ./...

Ingest Terraform state:

go run ./cmd/terratally ingest-state \
  --workspace-id prod-network \
  --repository acme/infra \
  --terraform-root envs/prod/network \
  --state-json state.json \
  --account-id 123456789012 \
  --region ap-northeast-1

Record an apply event:

go run ./cmd/terratally record-apply \
  --workspace-id prod-network \
  --repository acme/infra \
  --commit-sha abc123 \
  --status success \
  --pr-number 123 \
  --plan-json tfplan.json

Import AWS CUR aggregate CSV and attribute costs:

go run ./cmd/terratally import-aws-cur \
  --csv cur.csv \
  --from 2026-05-01 \
  --to 2026-06-01

go run ./cmd/terratally attribute \
  --from 2026-05-01 \
  --to 2026-06-01

Generate a report:

go run ./cmd/terratally report resources \
  --from 2026-05-01 \
  --to 2026-06-01 \
  --format markdown

CLI

Build the CLI:

go build -o ./bin/terratally ./cmd/terratally

Common commands:

go run ./cmd/terratally checklist aws-cur --format markdown
go run ./cmd/terratally import-aws-cur --athena-database cur_db --athena-table cur_table --from 2026-05-01 --to 2026-06-01 --dry-run
go run ./cmd/terratally report unmatched --from 2026-05-01 --to 2026-06-01 --format csv
go run ./cmd/terratally serve --host 127.0.0.1 --port 8787

Default paths:

  • Ledger: .terratally/ledger.json
  • Config: .terratally.yaml

Use --ledger and --config to override them.

Configuration

Start from .terratally.example.yaml. It defines workspaces, AWS Athena/CUR settings, ownership rules, tag aliases, redaction, attribution behavior, and report defaults.

Ownership precedence:

  1. Terraform tags: Owner, Team, Service, Environment, or configured aliases.
  2. .terratally.yaml ownership rules.
  3. CODEOWNERS.
  4. PR author team mapping.
  5. Git last author, when ownership.git_blame is enabled.
  6. Workspace default owner.
  7. unknown.

Billing CSV Shape

import-aws-cur accepts Athena-style aggregate CSV:

usage_date,account_id,region,product_code,usage_type,operation,resource_id,tag_owner,tag_service,unblended_cost
2026-05-11,123456789012,ap-northeast-1,AmazonEC2,BoxUsage,RunInstances,i-abc,team-platform,checkout,12.34

Athena SQL can be generated with:

go run ./cmd/terratally import-aws-cur \
  --athena-database cur_db \
  --athena-table cur_table \
  --from 2026-05-01 \
  --to 2026-06-01 \
  --dry-run

API And Dashboard

Start the API:

go run ./cmd/terratally serve --host 127.0.0.1 --port 8787

Dashboard:

http://127.0.0.1:8787/dashboard

Main endpoints:

  • GET /api/v1/costs/resources
  • GET /api/v1/costs/modules
  • GET /api/v1/costs/owners
  • GET /api/v1/costs/prs/{owner}/{repo}/{pr_number}
  • GET /api/v1/attribution/unmatched
  • GET /api/v1/attribution/tag-remediation
  • GET /api/v1/metrics
  • POST /api/v1/apply-events
  • POST /api/v1/state-snapshots
  • POST /api/v1/imports/aws-cur
  • POST /api/v1/imports/azure-cost
  • POST /api/v1/imports/gcp-billing
  • POST /api/v1/attribute

Set TERRATALLY_API_TOKEN or pass --api-token to require bearer auth for API routes.

PostgreSQL

Schema and views:

Export the local ledger as SQL:

go run ./cmd/terratally export-sql --output ledger.sql

Push to PostgreSQL:

DATABASE_URL=postgres://user:pass@host:5432/db \
go run ./cmd/terratally push-postgres

Security Notes

  • Raw Terraform state is not persisted.
  • Only identity/tag-related allowlisted attributes are stored.
  • Configure tag redaction for sensitive tag keys.
  • Do not run state or billing ingestion from untrusted external pull requests.
  • Use least-privilege AWS, GitHub, Slack, and database credentials.

Development

go test ./...
go vet ./...
go run ./cmd/terratally --help

More examples are in docs/quickstart.md.

About

Terraform cost attribution CLI/API for mapping cloud billing costs to Terraform resources, modules, owners, and pull requests.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages