Skip to content

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:

ModelAccuracyComplexityUse Case
Direct chargeback100%HighDepartment billing
Showback80-90%MediumCost awareness
No allocationN/ALowShared platforms

Direct Chargeback

Implementation

# Direct chargeback calculation
import boto3
import pandas as pd
from 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 usage
calculator = 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 usage
calculator = 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 usage
allocator = CostAllocator(shared_costs={'warehouse': 10000})
# Proportional allocation
team_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 allocation
fixed = 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 airflow
from airflow import DAG
from airflow.operators.python import PythonOperator
from airflow.providers.snowflake.operators.snowflake import SnowflakeOperator
from 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 chargeback
calculate_chargeback = PythonOperator(
task_id='calculate_chargeback',
python_callable=calculate_monthly_chargeback,
dag=dag
)
# Send chargeback reports
send_reports = PythonOperator(
task_id='send_reports',
python_callable=send_chargeback_emails,
dag=dag
)
# Upload to database
upload_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_reports

Chargeback 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 teams

DON’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 inaccuracies

Key Takeaways

  1. Direct chargeback: Most accurate, actual costs
  2. Showback: Cost visibility without billing
  3. Tag-based: Use cost center tags for allocation
  4. Proportional: Fair allocation based on usage
  5. Automation: Monthly chargeback calculation
  6. Documentation: Essential for transparency
  7. Dashboards: Make costs visible to teams
  8. Use When: Multi-team environments, cost accountability

Back to Module 7