Skip to content

sunilp303/s3-finops-optimizer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 

Repository files navigation

S3 Finops Optimizer

FinOps Team

Multi-account S3 Finops Optimizer -- a cost analysis tool that scans every bucket across an AWS Organization via AWSControlTowerExecution role assumption and produces actionable cost-reduction recommendations with estimated monthly savings.


What It Does

  • Scans one account, a specific account, or all active accounts in the AWS Organization
  • Pulls storage metrics from CloudWatch (14-day window to catch daily emission lag)
  • Pulls actual S3 spend from Cost Explorer
  • Analyzes every bucket for 9 cost and security issues
  • Estimates potential monthly savings per bucket and per account
  • Outputs results as a terminal report, PDF, Excel workbook, JSON, or CSV

Checks Performed

# Check Severity How Savings Are Estimated
1 Versioning enabled with no NoncurrentVersionExpiration rule HIGH 30% of current bucket cost
2 Incomplete multipart uploads with no AbortIncompleteMultipartUpload rule MEDIUM ~5 GB per upload × STANDARD price
3 STANDARD storage with no lifecycle transitions HIGH 50% of STANDARD GB moved to STANDARD-IA
4 Reduced Redundancy Storage (RRS) — costs more than STANDARD CRITICAL Price delta × RRS GB
5 S3 Intelligent-Tiering not enabled on large STANDARD buckets MEDIUM 40% of STANDARD GB at IT savings rate
6 No lifecycle policy at all MEDIUM Informational
7 Cross-region / cross-account replication active INFO Informational
8 Public access not fully blocked HIGH Informational
9 Empty bucket (possible orphan) LOW Informational

Requirements

Python 3.8+

pip install boto3 tabulate reportlab openpyxl
Package Required for
boto3 AWS API calls (required)
tabulate Formatted terminal tables (optional, degrades gracefully)
reportlab PDF output (optional)
openpyxl Excel output (optional)

AWS Permissions

Management / source account

organizations:ListAccounts
sts:AssumeRole

AWSControlTowerExecution role in each member account

s3:ListAllMyBuckets
s3:GetBucketLocation
s3:GetBucketVersioning
s3:GetLifecycleConfiguration
s3:ListBucketMultipartUploads
s3:GetBucketReplication
s3:GetBucketPublicAccessBlock
s3:ListBucketIntelligentTieringConfigurations
cloudwatch:GetMetricStatistics
ce:GetCostAndUsage

Note: The tool reads only — it makes no changes to any bucket, policy, or configuration.


Usage

Scan scope

# Current account only — no role assumption
python s3_cost_analyzer.py --scope single

# All active accounts in the AWS Organization
python s3_cost_analyzer.py --scope all

# Interactive numbered account picker
python s3_cost_analyzer.py --scope pick

# One specific account by ID
python s3_cost_analyzer.py --account-id 123456789012

Output formats

# Rich terminal report (default)
python s3_cost_analyzer.py --scope all

# Executive PDF (4 pages: KPI summary, per-account table, findings, bucket inventory)
python s3_cost_analyzer.py --scope all --output pdf

# Excel workbook (4 sheets: Executive Summary, All Findings, Bucket Detail, Quick Wins)
python s3_cost_analyzer.py --scope all --output excel

# Terminal + PDF + Excel in one run
python s3_cost_analyzer.py --scope all --output all

# Machine-readable JSON (pipe to jq, Lambda, Slack, etc.)
python s3_cost_analyzer.py --scope all --output json

# CSV — one row per bucket
python s3_cost_analyzer.py --scope all --output csv > s3_report.csv

Custom output file paths

python s3_cost_analyzer.py --scope all --output all \
  --pdf-path   SP_s3_apr2026.pdf \
  --excel-path SP_s3_apr2026.xlsx

Custom role name

If your cross-account role has a different name than AWSControlTowerExecution:

python s3_cost_analyzer.py --scope all --role-name MyCustomCrossAccountRole

AWS profile

python s3_cost_analyzer.py --scope all --profile SP-management

Output Reference

Terminal (--output text)

Account: 123456789012  (SP-prod)
-----------------------------------------------------------------------
CE S3 spend last 30 days: $8,200.00
Scanning 142 bucket(s)...

    -> my-data-bucket       2 finding(s)   18.4 GB   ~$0.42/mo
    -> my-logs-bucket       OK             2.1 GB    ~$0.05/mo
    ...

FULL BUCKET INVENTORY
FINDINGS & RECOMMENDATIONS
PER-ACCOUNT SUMMARY
QUICK WIN CHECKLIST

PDF (--output pdf)

Four-page report with SP navy/gold branding:

Page Content
1 Cover banner + 7 KPI summary boxes
2 Per-account cost table
3 All findings sorted by severity (CRITICAL → INFO)
4 Full bucket inventory + Quick win checklist

Excel (--output excel)

Sheet Content
Executive Summary KPI boxes, per-account table with SUM formulas, totals row
All Findings Color-coded severity badges, detail + action columns, auto-filter
Bucket Detail Full inventory, sortable, auto-filter
Quick Wins 10-item checklist with a Done? column

JSON (--output json)

{
  "scan_time": "2026-04-08T12:00:00Z",
  "grand_est_monthly_cost": 16919.33,
  "grand_est_savings": 4230.10,
  "grand_ce_spend_30d": 16919.33,
  "skipped_accounts": [],
  "buckets": [
    {
      "account_id": "123456789012",
      "account_name": "SP-prod",
      "bucket": "my-data-bucket",
      "region": "us-east-1",
      "total_gb": 18.4,
      "obj_count": 12400,
      "est_cost_mo": 0.42,
      "versioning": "Enabled",
      "lifecycle": "No",
      "mpu_count": 0,
      "replication": false,
      "public_blocked": true,
      "est_savings": 0.13,
      "recommendations": [ ... ]
    }
  ]
}

Terminal Encoding

Color codes and Unicode box-drawing characters are emitted only when stdout is a real interactive TTY. They are suppressed automatically when:

  • Output is piped or redirected (> file, | tee)
  • Running in Windows cmd.exe or PowerShell without VT100 support
  • The NO_COLOR=1 environment variable is set
# Force plain ASCII output in any environment
NO_COLOR=1 python s3_cost_analyzer.py --scope all --output excel

Architecture

Management account credentials
        │
        ├── --scope single   ──► use base session directly
        │
        ├── --scope pick     ──► organizations:ListAccounts
        │                         └─ interactive prompt
        │                              └─ sts:AssumeRole ──► member session
        │
        └── --scope all      ──► organizations:ListAccounts
                                  └─ for each active account:
                                       └─ sts:AssumeRole into AWSControlTowerExecution
                                            ├── s3:ListAllMyBuckets
                                            ├── cloudwatch:GetMetricStatistics (14d window)
                                            ├── ce:GetCostAndUsage (30d window)
                                            └── per-bucket S3 API calls
                                                 └─ _safe() wrapper — one failing check
                                                    never blocks the rest of the bucket

Accounts where role assumption fails (e.g. blocked by SCP, role missing) are skipped with a warning — the scan continues and skipped accounts are listed in the final report.


Pricing Reference

Storage class prices used for savings estimates (us-east-1, April 2026 — update STORAGE_PRICE_PER_GB in the script if AWS pricing changes):

Storage Class $/GB/mo
STANDARD $0.023
STANDARD_IA $0.0125
ONEZONE_IA $0.010
INTELLIGENT_TIERING $0.023
GLACIER_IR $0.004
GLACIER $0.0036
DEEP_ARCHIVE $0.00099
REDUCED_REDUNDANCY (legacy) $0.024

Quick Win Checklist

These are the highest-impact actions regardless of which specific buckets are flagged:

  1. AbortIncompleteMultipartUpload lifecycle rule — 7 days — all buckets
  2. NoncurrentVersionExpiration — 30 days — all versioned buckets
  3. Transition STANDARD → STANDARD_IA after 30 days — large cold buckets
  4. Transition STANDARD_IA → GLACIER after 90 days — archive workloads
  5. Enable S3 Intelligent-Tiering on variable-access buckets
  6. Migrate Reduced Redundancy Storage to STANDARD immediately
  7. Enable S3 Storage Lens org-wide for unified visibility
  8. Enable Cost Allocation Tags on all buckets
  9. Delete empty / orphaned buckets
  10. Block Public Access on all non-CDN buckets

Known Limitations

Limitation Detail
CloudWatch metric lag BucketSizeBytes is published once per day and can lag 24–48 h. The script uses a 14-day lookback window to compensate. Very new buckets may still show 0 GB.
Cost Explorer granularity CE spend is pulled at the account level, not per bucket. Per-bucket cost breakdown requires S3 Storage Lens with advanced metrics enabled.
Savings are estimates Estimates assume 50% of STANDARD data is cold, 40% of IT savings apply, etc. Actual savings depend on access patterns.
Role assumption Requires AWSControlTowerExecution (or equivalent) to exist and be assumable from the management account. Accounts with blocking SCPs are skipped.
Read-only The script makes no changes to any resource.

Files

s3_cost_analyzer.py     Main script
README.md               This file
s3_cost_report.pdf      Generated PDF (if --output pdf or --output all)
s3_cost_report.xlsx     Generated Excel (if --output excel or --output all)

Maintainer

sunilp303 GitHub org

About

A multi-account S3 cost analysis tool that scans all buckets across an AWS Organization , delivering actionable cost optimization recommendations along with estimated monthly savings.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages