Appearance
Monthly Cost Reporting
Purpose
This document describes the automated monthly cloud cost reporting pipeline — what it covers, when it runs, how to read the report, and how to act on findings.
Schedule and Delivery
| Setting | Value |
|---|---|
| Schedule | 1st of each month, 12:00 UTC |
| Delivery | HTML email via Amazon SES |
| Sender | ops-automation (Logging account, us-west-2) |
| Retention | GitHub Actions artifacts, 13-month retention (enables year-over-year comparison) |
The report runs automatically via GitHub Actions in the ops-automation repo. No manual trigger is required under normal operation.
Coverage
The report covers all three cloud environments in a single consolidated email.
Azure Production (ciriusgroup.com)
| Data | Source |
|---|---|
| Per-subscription costs | Azure Cost Management REST API |
| Month-over-month comparison | Current month vs. previous month |
| Advisor recommendations | Right-sizing, reserved instances, shutdown candidates |
| Waste items | Unattached managed disks, unattached public IPs, deallocated VMs with disk charges |
Azure DDE (ciriusdde.com)
| Data | Source |
|---|---|
| Per-subscription costs | Azure Cost Management REST API |
| DDE Advisor recommendations | DDE-Firewall and DDE-Billings right-sizing |
AWS (7-account org)
| Data | Source |
|---|---|
| Org-wide costs by service | AWS Cost Explorer API |
| Per-account breakdown | All 7 accounts |
| Waste detection | Idle EC2, unattached EBS, old snapshots, unused Elastic IPs |
| Anomaly detection | AWS Cost Anomaly Detection findings |
Note: AWS Cost Explorer API costs approximately $0.01 per call (~$0.04/month total).
Reading the Report
Display Name Overrides
Some Azure subscription/resource group names are internal identifiers. The report applies display name overrides for clarity:
| Internal Name | Report Display Name |
|---|---|
CiriusCustomers | Dashboard |
Billings | AVD |
| (empty Azure service name) | Prepaid/Reserved Compute |
Month-over-Month Comparison
Each section shows current month spend vs. the previous calendar month. Azure uses inclusive end dates; AWS uses exclusive end dates (first of next month). This is handled automatically in the pipeline — totals are comparable.
Waste Items
Waste items are resources costing money without apparent active use:
| Waste Type | What to Check |
|---|---|
| Unattached managed disks | Confirm disk is not needed, then delete. Azure portal → Disks → filter by "Unattached" |
| Unattached public IPs | Confirm IP is not reserved for future use, then delete |
| Deallocated VMs | Decide: delete, resize, or leave deallocated (disk charges continue even when stopped) |
| Unattached EBS volumes | Confirm not needed, then delete or snapshot first |
| Old snapshots / AMIs | Review age and necessity — AMIs registered without associated instances accumulate cost |
Advisor Recommendations
Azure Advisor recommendations are actionable optimization suggestions from Microsoft. Each recommendation in the report includes:
- Resource name and subscription
- Recommended action
- Estimated monthly savings
Act on recommendations where the action is safe. Dismiss recommendations that are intentional configurations (e.g., an oversized VM kept large for burst capacity).
Acting on Findings
Standard Monthly Review Process
- Review the email when it arrives on the 1st of the month
- Check for anomalies — any subscription showing a large month-over-month increase warrants investigation
- Action waste items — use the Azure portal and AWS console to clean up identified waste
- Review Advisor recommendations — implement where safe, dismiss where intentional
- Track savings — document monthly savings from cleanup actions (reference: March 2026 cleanup identified ~$221/month AWS savings, ~$315-420/month Azure waste)
Escalation
If the report shows unexpected spend significantly above trend (e.g., >20% month-over-month spike with no known cause):
- Check for newly provisioned resources in the affected subscription/account
- Check for data transfer charges (often caused by unexpected inter-region traffic)
- Check AWS Cost Anomaly Detection findings for root cause clues
- Review GitHub Actions recent runs for any unintended resource deployments
Pipeline Architecture
GitHub Actions (cron: 1st of month)
│
├── Azure Cost Management API (prod tenant)
├── Azure Cost Management API (DDE tenant)
└── AWS Cost Explorer API (management account → all 7 accounts)
│
HTML email assembled
│
Amazon SES → recipient email
│
Results stored as
GitHub Actions artifact
(13-month retention)Authentication: OIDC federated credentials across all three environments. The ops-automation OIDC trust is scoped to repo:Cirius-Group-Inc/ops-automation:ref:refs/heads/main on each environment's app registration / IAM role.
CLI and GitHub Actions role unified: The github-deploy-main IAM role is used for both CLI and GitHub Actions in the AWS environment.
Troubleshooting
| Symptom | Likely Cause | Resolution |
|---|---|---|
| Workflow fails to run | OIDC token expired or trust mismatch | Check federated credential subject in Entra ID / AWS IAM |
| Azure costs showing unexpectedly low | Previous-month date range issue (Azure inclusive vs. exclusive) | Review date parameters in Azure Cost Management API call |
| AWS Cost Explorer returns no data | Cost Explorer not enabled on management account | Enable Cost Explorer in AWS Billing console |
| Email not received | SES delivery failure or identity not verified | Check SES send statistics in Logging account |
Document History
| Date | Change | Author |
|---|---|---|
| March 2026 | Initial draft — cost report operational | Rory |