← Back to list

Automating AWS Cost Reports with a Webex Bot and AWS Lambda

In this blog post, we will walk through the process of setting up a Webex bot that retrieves AWS Cost and Usage Reports (CUR) using AWS…

Aadhith · 2025-02-28 05:39 · 4 claps · 3.6 min read
#aws #finops #lambda #cost-optimization #webex
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud

Automating AWS Cost Reports with a Webex Bot and AWS Lambda

In this blog post, we will walk through the process of setting up a Webex bot that retrieves AWS Cost and Usage Reports (CUR) using AWS Lambda. This setup enables you to get cost breakdowns across AWS accounts via a simple Webex chat command.

Overview

The solution consists of three key steps:

  1. Create a Webex bot and add it to a Webex space.
  2. Deploy an AWS Lambda function with an API Gateway trigger.
  3. Set up a Webex webhook to send and receive messages.

Step 1: Create a Webex Bot and Add It to a Space

  1. Navigate to the Webex Developer Portal.
  2. Sign in and go to My Apps > Create a Bot.
  3. Provide a bot name, username, and icon, then generate the bot token.
  4. Copy and save the bot token securely.
  5. Add the bot to a Webex space where it will respond to cost inquiries.

Step 2: Deploy AWS Lambda with API Gateway

Create a Lambda Function

  1. Open the AWS Lambda console and create a new function.
  2. Select Author from scratch, provide a function name, and choose Python as the runtime.
  3. Assign necessary permissions for accessing AWS Cost Explorer and Organizations API.

Deploy the Code

Use the following Python script for your Lambda function:

import json
import boto3
import datetime
import urllib3
# Webex API & Bot Token
WEBEX_BOT_TOKEN = "your_bot_token_here"
WEBEX_API_URL = "https://webexapis.com/v1"
http = urllib3.PoolManager()
# Get Webex Bot's Person ID
def get_bot_person_id():
    url = f"{WEBEX_API_URL}/people/me"
    headers = {"Authorization": f"Bearer {WEBEX_BOT_TOKEN}"}
    response = http.request("GET", url, headers=headers)
    if response.status == 200:
        return json.loads(response.data.decode("utf-8")).get("id")
    return None
BOT_PERSON_ID = get_bot_person_id()
# Get current month's date range
def get_current_month():
    today = datetime.date.today()
    start_of_month = today.replace(day=1)
    return start_of_month.strftime('%Y-%m-%d'), today.strftime('%Y-%m-%d')
# Get all AWS accounts
def get_all_accounts():
    org_client = boto3.client('organizations')
    accounts = []
    paginator = org_client.get_paginator('list_accounts')
    for page in paginator.paginate():
        for account in page['Accounts']:
            if account['Status'] == 'ACTIVE':
                accounts.append({'Id': account['Id'], 'Name': account['Name']})
    return accounts
# Get AWS cost for an account
def get_total_cost(account_id, start_date, end_date):
    ce_client = boto3.client('ce')
    response = ce_client.get_cost_and_usage(
        TimePeriod={'Start': start_date, 'End': end_date},
        Granularity='MONTHLY',
        Metrics=['UnblendedCost'],
        Filter={'Dimensions': {'Key': 'LINKED_ACCOUNT', 'Values': [account_id]}}
    )
    return float(response.get('ResultsByTime', [])[0].get('Total', {}).get('UnblendedCost', {}).get('Amount', 0))
# Generate cost report in Markdown format
def generate_markdown(accounts_sorted):
    markdown = "### AWS Cost Report by Account\n\n```
"
    markdown += "| {:<50} | {:>10} |\n".format("Account Name (ID)", "Cost (USD)")
    markdown += "|" + "-"*52 + "|" + "-"*12 + "|\n"

    for account, total_cost in accounts_sorted:
        account_str = f"{account['Name']} ({account['Id']})"
        if len(account_str) > 50:
            account_str = account_str[:47] + "..."
        account_str = account_str.ljust(50)
        cost_str = f"${total_cost:,.2f}".rjust(10)
        markdown += f"| {account_str} | {cost_str} |\n"
    markdown += "```
"
    return markdown
# Send cost report to Webex
def send_to_webex(report, room_id):
    url = f"{WEBEX_API_URL}/messages"
    headers = {
        "Authorization": f"Bearer {WEBEX_BOT_TOKEN}",
        "Content-Type": "application/json"
    }

    max_length = 7000  # Keeping below Webex limit
    report_chunks = [report[i:i+max_length] for i in range(0, len(report), max_length)]

    for chunk in report_chunks:
        payload = json.dumps({"roomId": room_id, "markdown": chunk})
        response = http.request("POST", url, body=payload, headers=headers)

    return response.status
# Main Lambda function
def lambda_handler(event, context):
    body = json.loads(event['body'])

    if 'data' in body:
        message_id = body['data']['id']
        room_id = body['data']['roomId']
        sender_id = body['data']['personId']

        if sender_id == BOT_PERSON_ID:
            return {"statusCode": 200, "body": "Ignored bot message"}

        message_details = fetch_message_details(message_id)
        user_message = message_details.get("text", "").lower()

        if "cost report" in user_message:
            start_date, end_date = get_current_month()
            accounts = get_all_accounts()
            account_costs = [(account, get_total_cost(account['Id'], start_date, end_date)) for account in accounts]
            account_costs.sort(key=lambda x: x[1], reverse=True)
            markdown_report = generate_markdown(account_costs)
            send_to_webex(markdown_report, room_id)

    return {"statusCode": 200, "body": "Processed"}

Create an API Gateway Trigger

  1. Navigate to API Gateway and create a new REST API.
  2. Set up a POST method for the resource and link it to the Lambda function.
  3. Deploy the API and copy the invoke URL.

Step 3: Add Webex Webhook

Run the following command to register a webhook that forwards messages to the Lambda function:

curl -X POST "https://webexapis.com/v1/webhooks" \                          
-H "Authorization: Bearer YOUR_BOT_TOKEN" \  
-H "Content-Type: application/json" \  
-d '{
    "name": "Cost Report",
    "targetUrl": "YOUR_API_GATEWAY_URL",
    "resource": "messages",
    "event": "created"
}'

Once set up, your Webex bot will respond with AWS cost reports when prompted in a chat.

As an alternative approach to this, you can also schedule the AWS cost report using Amazon EventBridge to trigger the Lambda function at a set interval, such as daily or monthly. Instead of relying on Webex message triggers, the Lambda function can fetch cost data automatically and send the report using a Webex Incoming Webhook.


메타데이터
post_id
ff424e7b8c79
slug
automating-aws-cost-reports-with-a-webex-bot-and-aws-lambda-ff424e7b8c79
url
https://medium.com/@aadhith/automating-aws-cost-reports-with-a-webex-bot-and-aws-lambda-ff424e7b8c79
canonical_url
https://medium.com/@aadhith/automating-aws-cost-reports-with-a-webex-bot-and-aws-lambda-ff424e7b8c79
author_url
https://medium.com/@aadhith
status
ok
fetched_at
2026-07-20 20:15:43