diff --git a/infrastructure/terraform/components/acct/README.md b/infrastructure/terraform/components/acct/README.md
index ade163fd3..041f69a1b 100644
--- a/infrastructure/terraform/components/acct/README.md
+++ b/infrastructure/terraform/components/acct/README.md
@@ -13,7 +13,10 @@
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| [aws\_account\_id](#input\_aws\_account\_id) | The AWS Account ID (numeric) | `string` | n/a | yes |
+| [budget\_amount](#input\_budget\_amount) | The budget amount in USD for the account | `number` | `500` | no |
| [component](#input\_component) | The variable encapsulating the name of this component | `string` | `"acct"` | no |
+| [cost\_alarm\_recipients](#input\_cost\_alarm\_recipients) | A list of email addresses to receive alarm notifications | `list(string)` | `[]` | no |
+| [cost\_anomaly\_threshold](#input\_cost\_anomaly\_threshold) | The threshold percentage for cost anomaly detection | `number` | `10` | no |
| [default\_tags](#input\_default\_tags) | A map of default tags to apply to all taggable resources within the component | `map(string)` | `{}` | no |
| [environment](#input\_environment) | The name of the tfscaffold environment | `string` | n/a | yes |
| [group](#input\_group) | The group variables are being inherited from (often synonmous with account short-name) | `string` | n/a | yes |
diff --git a/infrastructure/terraform/components/acct/budgets_budget.tf b/infrastructure/terraform/components/acct/budgets_budget.tf
new file mode 100644
index 000000000..6a253fa5c
--- /dev/null
+++ b/infrastructure/terraform/components/acct/budgets_budget.tf
@@ -0,0 +1,31 @@
+resource "aws_budgets_budget" "main" {
+ name = "${local.csi}-monthly-budget"
+ budget_type = "COST"
+ limit_amount = var.budget_amount
+ limit_unit = "USD"
+ time_unit = "MONTHLY"
+
+ notification {
+ comparison_operator = "GREATER_THAN"
+ notification_type = "FORECASTED"
+ threshold = 100
+ threshold_type = "PERCENTAGE"
+ subscriber_sns_topic_arns = [aws_sns_topic.costs.arn]
+ }
+
+ notification {
+ comparison_operator = "GREATER_THAN"
+ notification_type = "ACTUAL"
+ threshold = 100
+ threshold_type = "PERCENTAGE"
+ subscriber_sns_topic_arns = [aws_sns_topic.costs.arn]
+ }
+
+ notification {
+ comparison_operator = "GREATER_THAN"
+ notification_type = "ACTUAL"
+ threshold = 85
+ threshold_type = "PERCENTAGE"
+ subscriber_sns_topic_arns = [aws_sns_topic.costs.arn]
+ }
+}
diff --git a/infrastructure/terraform/components/acct/cost_anomaly_monitor.tf b/infrastructure/terraform/components/acct/cost_anomaly_monitor.tf
new file mode 100644
index 000000000..986336a91
--- /dev/null
+++ b/infrastructure/terraform/components/acct/cost_anomaly_monitor.tf
@@ -0,0 +1,28 @@
+resource "aws_ce_anomaly_monitor" "anomaly_monitor" {
+ name = "${local.csi}-anomaly-monitor"
+ monitor_type = "DIMENSIONAL"
+ monitor_dimension = "SERVICE"
+}
+
+resource "aws_ce_anomaly_subscription" "realtime_subscription" {
+ name = "${local.csi}-realtime-subscription"
+ frequency = "IMMEDIATE"
+ threshold_expression {
+ dimension {
+ key = "ANOMALY_TOTAL_IMPACT_PERCENTAGE"
+ values = [var.cost_anomaly_threshold]
+ match_options = ["GREATER_THAN_OR_EQUAL"]
+ }
+ }
+ monitor_arn_list = [
+ aws_ce_anomaly_monitor.anomaly_monitor.arn,
+ ]
+
+ subscriber {
+ type = "SNS"
+ address = aws_sns_topic.costs.arn
+ }
+ depends_on = [
+ aws_sns_topic_policy.costs,
+ ]
+}
diff --git a/infrastructure/terraform/components/acct/sns_topic_costs.tf b/infrastructure/terraform/components/acct/sns_topic_costs.tf
new file mode 100644
index 000000000..50b544d1c
--- /dev/null
+++ b/infrastructure/terraform/components/acct/sns_topic_costs.tf
@@ -0,0 +1,37 @@
+resource "aws_sns_topic" "costs" {
+ name = "${local.csi}-costs"
+ kms_master_key_id = module.kms.key_id
+}
+
+resource "aws_sns_topic_policy" "costs" {
+ arn = aws_sns_topic.costs.arn
+
+ policy = data.aws_iam_policy_document.sns_costs.json
+}
+
+data "aws_iam_policy_document" "sns_costs" {
+ statement {
+ sid = "AllowSNSCosts"
+ effect = "Allow"
+
+ actions = [
+ "SNS:Publish",
+ ]
+
+ resources = [
+ aws_sns_topic.costs.arn,
+ ]
+
+ principals {
+ type = "Service"
+ identifiers = ["budgets.amazonaws.com", "costalerts.amazonaws.com"]
+ }
+ }
+}
+
+resource "aws_sns_topic_subscription" "costs" {
+ for_each = toset(var.cost_alarm_recipients)
+ topic_arn = aws_sns_topic.costs.arn
+ protocol = "email"
+ endpoint = each.value
+}
diff --git a/infrastructure/terraform/components/acct/variables.tf b/infrastructure/terraform/components/acct/variables.tf
index 92bbdb840..1a9f5be07 100644
--- a/infrastructure/terraform/components/acct/variables.tf
+++ b/infrastructure/terraform/components/acct/variables.tf
@@ -120,3 +120,21 @@ variable "oam_sink_id" {
type = string
default = ""
}
+
+variable "cost_alarm_recipients" {
+ type = list(string)
+ description = "A list of email addresses to receive alarm notifications"
+ default = []
+}
+
+variable "budget_amount" {
+ type = number
+ description = "The budget amount in USD for the account"
+ default = 500
+}
+
+variable "cost_anomaly_threshold" {
+ type = number
+ description = "The threshold percentage for cost anomaly detection"
+ default = 10
+}