Cross-Cloud Cost Anomaly Detection: One Methodology for Azure and AWS
If you run Azure and AWS, you currently have two different definitions of "cost anomaly" — and neither of them is yours. Azure Cost Management flags what Microsoft's model finds unusual, at subscription scope, by email. AWS Cost Anomaly Detection flags what Amazon's model finds unusual, per monitor, with its own thresholds. The same $400 step change can alert on one cloud and pass silently on the other, and nobody can tell you why. This article compares the two native services honestly — they're both free and both worth enabling — and then walks through the unified, auditable methodology we built so a cross-cloud estate gets one answer to "was that normal?"
The native services, side by side
Both providers ship a free, ML-based anomaly detector, and we've covered each in depth — see Azure cost anomaly detection and AWS Cost Anomaly Detection for setup walkthroughs. Put next to each other, the differences matter:
| Azure Cost Management anomaly alerts | AWS Cost Anomaly Detection | |
|---|---|---|
| Scope | Subscription only — no resource group, service, or management group monitors. | Flexible monitors: per service, per linked account, per cost category or allocation tag. |
| Tunability | None. You can't set a threshold, a floor, or a sensitivity. | Partial. Alert thresholds (absolute $ and/or %) are yours; the detection model itself isn't. |
| Delivery | Email recipients on the alert rule. | Email or SNS — so Slack, PagerDuty, Lambda fan-out is easy. |
| Explanation | Flags the day; you dig from there. | Root-cause hints: service, account, Region, usage type, expected vs actual. |
| Warm-up | Needs history to model a pattern. | ~10 days of data before a monitor is useful. |
| Cost | Free. | Free. |
And the shared gaps — the reasons neither is sufficient on its own:
- Both are black boxes. Neither will show you the math behind a flag, so you can't explain to finance why Tuesday alerted and Wednesday didn't — or verify a miss.
- Both are weakest on gradual creep. A workload ramping 3% a day rarely trips a model that continuously re-learns "normal" — the model absorbs the drift. Log growth and snapshot sprawl live in this blind spot.
- Neither is consistent with the other. Different sensitivity, different scopes, different delivery — so your cross-cloud cost review has two incompatible anomaly feeds.
Why one methodology beats two models
For a single-cloud team, the native detector plus a monthly review is a fine baseline. For a cross-cloud estate, governance needs a portable definition: the same spend pattern should produce the same verdict on either cloud, and the verdict should be explainable. That rules out proprietary ML and points at deterministic robust statistics — published thresholds, recomputable by hand, fed by each cloud's billing API. Same math, two data sources.
The unified methodology, detector by detector
This is the engine inside the CloudFinOpsKit tools' Cost Anomaly Watch module — identical in the Azure and AWS kits, and fully specified in a published methodology document that ships with the tool. The data first, because the data rules prevent most false positives:
- ~92 days of daily cost per service, one series per service (per subscription on Azure) plus a scope-level total that catches distributed drift no single service trips.
- Usage charges only. RI and Savings Plan purchases, fees, refunds, credits, and tax are filtered at the source — otherwise every monthly commitment purchase would flag as a "spike."
- The trailing 2 days are excluded. Billing data on both clouds finalizes 8–72 hours behind; unfinalized days are the single biggest source of false anomalies.
Then five detectors run over every series:
| Detector | The rule | What it catches |
|---|---|---|
| Daily spike | Each day vs the median of its last ~10 same-weekday values; flag when the modified z-score (Iglewicz–Hoaglin, using MAD) is ≥ 3.5. | A runaway job, a scale-up that didn't scale back, a data-transfer blow-out — comparing Monday to Mondays removes weekday/weekend seasonality. |
| Step change | Median of the trailing 7 days vs median of the prior 21; flag on a ≥ 30% shift. Medians, so one spike day can't fake a step. | A deployment that permanently raised the run rate — deliberate or not, the costliest class when it's not. |
| Gradual creep | Theil–Sen slope (median of all pairwise slopes) over 30 days; flag when drift projects to ≥ 20% per month. | Log growth, snapshot sprawl, slowly scaling workloads — exactly the class both native models absorb into "normal." |
| New spend source | A series with essentially no history (< $1 total) that now averages real money per day. | Compromised keys mining crypto, accidental regions, unapproved services. |
| Vanished spend | An established series whose last 7 days all read ≤ 5% of baseline. Informational. | A decommission (good) — or a broken workload masquerading as savings. |
Two design decisions do most of the work:
- The dual gate. Every flag must clear both statistical significance and an absolute dollar floor (default $5/day, tunable). A dev subscription jumping from $0.30 to $1.20/day is a statistically massive 4× — and nobody should be paged for it.
- Median + MAD, not mean + standard deviation. Robust statistics don't let one past spike inflate the baseline and hide the next one. And because every number is published, any flag can be recomputed by hand from the figures in the report — "why did this alert?" always has an answer.
One anomaly feed for both clouds. The CloudFinOpsKit Azure Tool and the AWS Tool ship the same Cost Anomaly Watch module: schedule each daily, pass a Teams or Slack webhook, and High-severity anomalies from either cloud land in the same channel with expected vs actual figures, projected monthly impact, and the top contributing resources or usage types on the anomaly day. Same thresholds, same math, same definition of "anomaly" — plus the full methodology document so you can audit every flag.
Keep the native detectors on
This isn't a rip-and-replace. The native services are free, need minutes to enable, and run on the provider's schedule even when your tooling doesn't. The right posture is defense in depth: native alerts as the always-on baseline, the unified methodology as the layer that's consistent across clouds, explains itself, catches creep, and alerts where your team actually works. When both fire on the same event, you have confirmation; when only one does, you learn something about the other's blind spot.
FAQ
Can I get one anomaly definition across Azure and AWS?
Not from the native services — their models, scopes, and sensitivities differ and can't be aligned. Running the same deterministic methodology against both clouds' daily billing data is the only way to get one consistent, explainable definition of "anomaly" estate-wide.
Why same-weekday baselines instead of a trailing average?
Cloud spend has strong weekday/weekend seasonality — batch jobs, business-hours autoscale, dev machines off at weekends. A trailing average blends the two regimes and either misses Monday spikes or false-flags every Saturday. Comparing Monday to the last ~10 Mondays removes the seasonality by construction.
What about anomalies in AI spend?
Token-based spend needs its own detectors — dollar-level rules miss a model-mix shift entirely. The same module includes token-aware detection on both clouds; see detecting AI cost anomalies for the full treatment.
Related reading: Azure cost anomaly detection · AWS Cost Anomaly Detection · detecting AI cost anomalies · the cloud cost governance framework