Chargeback Models
Cost Allocation and Showback
Overview
Chargeback models allocate cloud costs to business units, projects, or teams, enabling cost accountability and optimization. Showback makes costs visible without actual billing.
Chargeback Models
Model Comparison
Model Selection:
| Model | Accuracy | Complexity | Use Case |
|---|---|---|---|
| Direct chargeback | 100% | High | Department billing |
| Showback | 80-90% | Medium | Cost awareness |
| No allocation | N/A | Low | Shared platforms |
Direct Chargeback
Implementation
# Direct chargeback calculation
import boto3import pandas as pdfrom datetime import datetime, timedelta
class ChargebackCalculator: """Calculate chargeback by cost center"""
def __init__(self): self.ce_client = boto3.client('ce', region_name='us-east-1')
def calculate_chargeback( self, start_date: str, end_date: str, tag_key: str = 'CostCenter' ) -> dict: """Calculate chargeback by cost center"""
# Get cost by tag response = self.ce_client.get_cost_and_usage( TimePeriod={ 'Start': start_date, 'End': end_date }, Granularity='MONTHLY', GroupBy=[ {'Type': 'TAG_KEY', 'Key': tag_key} ], Metrics=[ {'Name': 'UnblendedCost'}, {'Name': 'BlendedCost'} ] )
# Parse results chargeback = {} for result in response['ResultsByTime']: time_period = result['TimePeriod']['Start']
for group in result['Groups']: cost_center = None
# Extract cost center from keys for key in group['Keys']: if key['Key'] == tag_key: cost_center = key['Value'] break
if cost_center: if cost_center not in chargeback: chargeback[cost_center] = { 'unblended_cost': 0, 'blended_cost': 0, 'months': {} }
for metric in group['Metrics']: metric_name = metric['Name'] amount = float(metric['Amount'])
if metric_name == 'UnblendedCost': chargeback[cost_center]['unblended_cost'] += amount elif metric_name == 'BlendedCost': chargeback[cost_center]['blended_cost'] += amount
chargeback[cost_center]['months'][time_period] = { 'unblended_cost': chargeback[cost_center]['unblended_cost'], 'blended_cost': chargeback[cost_center]['blended_cost'] }
return chargeback
def generate_chargeback_report(self, chargeback: dict) -> pd.DataFrame: """Generate chargeback report"""
rows = [] for cost_center, data in chargeback.items(): rows.append({ 'cost_center': cost_center, 'unblended_cost': data['unblended_cost'], 'blended_cost': data['blended_cost'] })
df = pd.DataFrame(rows) df['blended_cost'] = df['blended_cost'].round(2) df['unblended_cost'] = df['unblended_cost'].round(2)
return df
# Example usagecalculator = ChargebackCalculator()
chargeback = calculator.calculate_chargeback( start_date='2025-01-01', end_date='2025-01-31', tag_key='CostCenter')
report = calculator.generate_chargeback_report(chargeback)print(report)Showback Model
Showback Implementation
# Showback (cost visibility without billing)
class ShowbackCalculator: """Calculate showback by team"""
def __init__(self): self.ce_client = boto3.client('ce', region_name='us-east-1')
def calculate_showback( self, start_date: str, end_date: str ) -> dict: """Calculate showback by team"""
# Get costs by multiple tags response = self.ce_client.get_cost_and_usage( TimePeriod={ 'Start': start_date, 'End': end_date }, Granularity='MONTHLY', GroupBy=[ {'Type': 'TAG_KEY', 'Key': 'Team'}, {'Type': 'TAG_KEY', 'Key': 'Service'} ], Metrics=[ {'Name': 'UnblendedCost'} ] )
# Parse results showback = {} for result in response['ResultsByTime']: for group in result['Groups']: team = None service = None
# Extract tags for key in group['Keys']: if key['Key'] == 'Team': team = key['Value'] elif key['Key'] == 'Service': service = key['Value']
cost = float(group['Metrics'][0]['Amount'])
if team and service: if team not in showback: showback[team] = {'total': 0, 'services': {}]
showback[team]['total'] += cost
if service not in showback[team]['services']: showback[team]['services'][service] = 0
showback[team]['services'][service] += cost
return showback
def generate_showback_dashboard(self, showback: dict) -> dict: """Generate showback dashboard data"""
dashboard = { 'teams': [] }
for team, data in showback.items(): dashboard['teams'].append({ 'team': team, 'total_cost': data['total'], 'services': data['services'] })
# Sort by cost dashboard['teams'].sort(key=lambda x: x['total_cost'], reverse=True)
return dashboard
# Example usagecalculator = ShowbackCalculator()
showback = calculator.calculate_showback( start_date='2025-01-01', end_date='2025-01-31')
dashboard = calculator.generate_showback_dashboard(showback)print(dashboard)Cost Allocation
Allocation Models
Allocation Implementation
# Cost allocation models
class CostAllocator: """Allocate shared costs to teams"""
def __init__(self, shared_costs: dict): self.shared_costs = shared_costs
def allocate_direct(self, direct_costs: dict) -> dict: """Direct allocation (actual costs)"""
# No allocation needed, actual costs return direct_costs
def allocate_proportional( self, shared_cost: float, team_usages: dict) -> dict: """Proportional allocation based on usage"""
total_usage = sum(team_usages.values())
allocation = {} for team, usage in team_usages.items(): allocation[team] = (usage / total_usage) * shared_cost
return allocation
def allocate_fixed_percentage( self, shared_cost: float, percentages: dict ) -> dict: """Fixed percentage allocation"""
allocation = {} for team, percentage in percentages.items(): allocation[team] = shared_cost * percentage
return allocation
# Example usageallocator = CostAllocator(shared_costs={'warehouse': 10000})
# Proportional allocationteam_usages = { 'engineering': 1000, # 1000 queries 'data_science': 500, # 500 queries 'analytics': 1500 # 1500 queries}
proportional = allocator.allocate_proportional( shared_cost=10000, team_usages=team_usages)
# Fixed percentage allocationfixed = allocator.allocate_fixed_percentage( shared_cost=10000, percentages={ 'engineering': 0.4, # 40% 'data_science': 0.3, # 30% 'analytics': 0.3 # 30% })Chargeback Automation
Automated Chargeback
# Automated chargeback with Airflow
import airflowfrom airflow import DAGfrom airflow.operators.python import PythonOperatorfrom airflow.providers.snowflake.operators.snowflake import SnowflakeOperatorfrom datetime import datetime, timedelta
default_args = { 'owner': 'finops', 'start_date': datetime(2025, 1, 1), 'depends_on_past': False,}
dag = DAG( 'monthly_chargeback', default_args=default_args, schedule_interval='0 0 1 * *', # First day of month catchup=False, tags=['finops', 'chargeback'])
# Calculate chargebackcalculate_chargeback = PythonOperator( task_id='calculate_chargeback', python_callable=calculate_monthly_chargeback, dag=dag)
# Send chargeback reportssend_reports = PythonOperator( task_id='send_reports', python_callable=send_chargeback_emails, dag=dag)
# Upload to databaseupload_to_snowflake = SnowflakeOperator( task_id='upload_to_snowflake', sql='INSERT INTO finops.chargeback SELECT * FROM TEMP_CHARGEBACK', dag=dag)
calculate_chargeback >> upload_to_snowflake >> send_reportsChargeback Best Practices
DO
# 1. Use direct chargeback when possible# Most accurate cost allocation
# 2. Showback for awareness# Without actual billing
# 3. Document allocation methodology# Essential for transparency
# 4. Review allocations quarterly# Adjust based on feedback
# 5. Make costs visible# Dashboards for all teamsDON’T
# 1. Don't chargeback randomly# Use fair allocation methods
# 2. Don't ignore shared resources# Allocate shared costs fairly
# 3. Don't forget overhead# Include platform overhead
# 4. Don't update allocation retroactively# Only forward-looking changes
# 5. Don't over-allocate# Round up causes inaccuraciesKey Takeaways
- Direct chargeback: Most accurate, actual costs
- Showback: Cost visibility without billing
- Tag-based: Use cost center tags for allocation
- Proportional: Fair allocation based on usage
- Automation: Monthly chargeback calculation
- Documentation: Essential for transparency
- Dashboards: Make costs visible to teams
- Use When: Multi-team environments, cost accountability
Back to Module 7