The bill on this account had roughly doubled over a year while the team swore nothing had changed. I pointed four open-source FinOps tools at it, one after another, to see which of them could explain why. Each one was useful. None of them was the answer, and the gaps were more interesting than the findings.

I am deliberately not going to give you a table of dollar figures. The numbers were specific to one account and would be misleading anywhere else. What transfers is the shape of what each tool sees, and, more importantly, the shape of what it does not.

Cost tooling does not fail by being wrong. It fails by being confidently incomplete.

Infracost: what it would cost, not what it does cost

Infracost reads Terraform and tells you the monthly price of what you are about to apply. It runs in CI, comments on the pull request, and it is genuinely the best guardrail I know for stopping an expensive change before it lands.

infracost breakdown --path ./infra --format table

What it found: two environments where the instance class had been bumped "temporarily" in a PR nobody had reverted. Infracost had flagged the increase at the time. The comment had been read and approved.

What it missed: everything that was not in Terraform. Around a third of this account had been created by hand in the console or by a script that had long since been deleted. Infracost has no opinion on those resources because it never sees them. It also prices what you declared, not what you use: an on-demand instance running at four percent CPU costs exactly the same on its report as one running flat out.

Komiser: the inventory you did not know you needed

Komiser connects to the account, walks every region and service it supports, and builds an inventory with a cost attached to each item. You get a dashboard, filters, tags, and the ability to answer "what do we actually have?" without opening twelve consoles.

What it found: the click-ops third that Infracost could not see. Load balancers with no targets. Elastic IPs attached to nothing. A NAT gateway in a region the team did not know they used. A cluster of snapshots from a migration that finished eighteen months ago. Just seeing the list was worth the setup.

What it missed: the "why". Komiser could tell me a resource existed and roughly what it cost, but not whether it was needed, not who owned it, and not whether the size was right. Inventory is the start of a conversation with the team, not a decision. Coverage also stops at the services it has integrations for, so a few of the more obscure line items on the bill never appeared.

Cloud Custodian: rules, but only the rules you wrote

Cloud Custodian is a policy engine. You describe a condition in YAML, it finds every resource matching that condition, and optionally acts on it: tag it, stop it, notify someone, delete it after a grace period. It is the tool I would pick if I could only keep one, because it turns a finding into a habit.

policies:
  - name: ebs-unattached-older-than-30-days
    resource: aws.ebs
    filters:
      - Attachments: []
      - type: value
        key: CreateTime
        value_type: age
        op: greater-than
        value: 30
    actions:
      - type: tag
        key: custodian_status
        value: unattached-30d

What it found: exactly what I asked for. Unattached volumes, stopped instances still holding storage, old snapshots, untagged resources. Once the policies existed, they ran every night and the list stopped growing.

What it missed: everything I had not thought to write a policy for. Custodian has no built-in notion of waste; it has filters. If you do not know that idle NAT gateways are a common leak, you will not write the rule, and Custodian will not tell you. It is also blind to pricing. It can find the oversized instance but cannot tell you what right-sizing it would save.

OpenCost: precise inside Kubernetes, silent outside it

OpenCost runs inside a cluster and allocates the cost of nodes down to namespaces, deployments and pods, using real usage rather than requests. If you run Kubernetes, it answers the question every platform team gets asked: which team is spending the money?

What it found: one namespace consuming most of the cluster's cost through a handful of pods whose resource requests were several times what they actually used. The nodes were sized for the requests. Nobody had looked in a year.

What it missed: the other seventy percent of the bill. OpenCost is Kubernetes-shaped by design. Managed databases, object storage, data transfer, the NAT gateways, the load balancers: none of it exists as far as OpenCost is concerned. It also relies on you having proper labels, and this cluster did not, so a meaningful slice of cost landed in the bucket called "unallocated", which is a polite name for "nobody".

What all four missed together

This is the part I actually wanted to learn. If you run all four, you get a decent inventory, a nightly cleanup, cost-aware pull requests and per-team allocation in the cluster. That is a lot. And yet the same handful of things fell through every tool.

What I would tell a team starting today

Use the free tools. They are good, and they will pay for the afternoon it takes to set them up many times over. Start with an inventory so you know what exists, add Custodian policies so the obvious waste stops accumulating, and put Infracost in CI so the next expensive change gets a comment before it merges.

Then be clear-eyed about the gap. The open-source layer finds waste. It does not find the reason, it does not see the commitments, it does not remember last quarter, and it does not know who to ask. That gap is where the money you are actually looking for tends to sit, and closing it needs either a person with time and context or a system built to hold both. On this account it was a person, for a while. It usually is, until it is not.