Files
terraform-foundation/terraform/modules/tenant-budget/main.tf
Greg Hendrickson 6136cde9bb feat: Terraform Foundation - AWS Landing Zone
Enterprise-grade multi-tenant AWS cloud foundation.

Modules:
- GitHub OIDC for keyless CI/CD authentication
- IAM account settings and security baseline
- AWS Config Rules for compliance
- ABAC (Attribute-Based Access Control)
- SCPs (Service Control Policies)

Features:
- Multi-account architecture
- Cost optimization patterns
- Security best practices
- Comprehensive documentation

Tech: Terraform, AWS Organizations, IAM Identity Center
2026-02-02 02:57:23 +00:00

145 lines
4.1 KiB
HCL

################################################################################
# Tenant Budget Module
#
# Creates tenant-specific budget with alerts:
# - Monthly budget with configurable limit
# - Multi-threshold alerts
# - Cost allocation tag filtering
# - SNS and email notifications
################################################################################
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}
}
data "aws_caller_identity" "current" {}
locals {
account_id = data.aws_caller_identity.current.account_id
# Build cost filters from tags
cost_filters = length(var.cost_filter_tags) > 0 ? {
TagKeyValue = [for k, v in var.cost_filter_tags : "user:${k}$${v}"]
} : {}
}
################################################################################
# SNS Topic for Budget Alerts
################################################################################
resource "aws_sns_topic" "budget" {
count = var.create_sns_topic ? 1 : 0
name = "${var.name}-budget-alerts"
tags = merge(var.tags, {
Name = "${var.name}-budget-alerts"
})
}
resource "aws_sns_topic_policy" "budget" {
count = var.create_sns_topic ? 1 : 0
arn = aws_sns_topic.budget[0].arn
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "AllowBudgetsPublish"
Effect = "Allow"
Principal = {
Service = "budgets.amazonaws.com"
}
Action = "sns:Publish"
Resource = aws_sns_topic.budget[0].arn
Condition = {
StringEquals = {
"aws:SourceAccount" = local.account_id
}
}
}
]
})
}
resource "aws_sns_topic_subscription" "email" {
for_each = var.create_sns_topic ? toset(var.notification_emails) : []
topic_arn = aws_sns_topic.budget[0].arn
protocol = "email"
endpoint = each.value
}
################################################################################
# Budget
################################################################################
resource "aws_budgets_budget" "this" {
name = "${var.name}-monthly-budget"
budget_type = "COST"
limit_amount = tostring(var.budget_limit)
limit_unit = "USD"
time_unit = "MONTHLY"
# Optional: Filter by cost allocation tags
dynamic "cost_filter" {
for_each = local.cost_filters
content {
name = cost_filter.key
values = cost_filter.value
}
}
cost_types {
include_credit = false
include_discount = true
include_other_subscription = true
include_recurring = true
include_refund = false
include_subscription = true
include_support = true
include_tax = true
include_upfront = true
use_amortized = false
use_blended = false
}
# Actual spend notifications
dynamic "notification" {
for_each = var.alert_thresholds
content {
comparison_operator = "GREATER_THAN"
threshold = notification.value
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_email_addresses = var.create_sns_topic ? [] : var.notification_emails
subscriber_sns_topic_arns = var.create_sns_topic ? [aws_sns_topic.budget[0].arn] : (var.sns_topic_arn != null ? [var.sns_topic_arn] : [])
}
}
# Forecasted spend notifications
dynamic "notification" {
for_each = var.enable_forecasted_alerts ? var.forecasted_thresholds : []
content {
comparison_operator = "GREATER_THAN"
threshold = notification.value
threshold_type = "PERCENTAGE"
notification_type = "FORECASTED"
subscriber_email_addresses = var.create_sns_topic ? [] : var.notification_emails
subscriber_sns_topic_arns = var.create_sns_topic ? [aws_sns_topic.budget[0].arn] : (var.sns_topic_arn != null ? [var.sns_topic_arn] : [])
}
}
tags = merge(var.tags, {
Name = "${var.name}-monthly-budget"
Tenant = var.name
})
}