Skip to content

Commit 5da10ad

Browse files
Merge pull request #41 from meshcloud/feature/gcp-budget-alert
feat: GCP budget alert building block
2 parents adadee1 + 61ef790 commit 5da10ad

File tree

15 files changed

+360
-8
lines changed

15 files changed

+360
-8
lines changed

modules/aws/budget-alert/buildingblock/README.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,14 @@ name: AWS Budget Alert
33
supportedPlatforms:
44
- aws
55
description: |
6-
Deploys an AWS Budget Alert to an AWS account.
6+
Sets up budget alerts for an AWS account to monitor spending and prevent cost overruns.
77
---
88

99
This Terraform module provisions AWS Budget Alerts to help you monitor and control your cloud spending.
1010

11-
## Features
11+
## Permissions
1212

13-
- Set monthly budget amounts for your AWS accounts
14-
- Configure email notifications based on actual spend thresholds
15-
- Configure email notifications based on forecasted spend thresholds
16-
- Easy integration with meshStack
13+
Please reference the [backplane implementation](../backplane/) for the required permissions to deploy this building block.
1714

1815
<!-- BEGIN_TF_DOCS -->
1916
## Requirements

modules/azure/budget-alert/buildingblock/README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ This documentation is intended as a reference documentation for cloud foundation
1313

1414
## Permissions
1515

16-
This is a very simple building block, which means we let the SPN have access to deploy budget alerts
17-
across all subscriptions underneath a management group (typically the top-level management group for landing zones).
16+
Please reference the [backplane implementation](../backplane/) for the required permissions to deploy this building block.
1817

1918
<!-- BEGIN_TF_DOCS -->
2019
## Requirements
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
## Permissions
2+
3+
This building block requires access to the organization's billing account and a dedicated GCP project to manage notification channels.
4+
5+
<!-- BEGIN_TF_DOCS -->
6+
## Requirements
7+
8+
| Name | Version |
9+
|------|---------|
10+
| <a name="requirement_google"></a> [google](#requirement\_google) | 6.12.0 |
11+
12+
## Modules
13+
14+
No modules.
15+
16+
## Resources
17+
18+
| Name | Type |
19+
|------|------|
20+
| [google_billing_account_iam_member.billing_viewer](https://registry.terraform.io/providers/hashicorp/google/6.12.0/docs/resources/billing_account_iam_member) | resource |
21+
| [google_billing_account_iam_member.budget_admin](https://registry.terraform.io/providers/hashicorp/google/6.12.0/docs/resources/billing_account_iam_member) | resource |
22+
| [google_project_iam_member.notification_channel_admin](https://registry.terraform.io/providers/hashicorp/google/6.12.0/docs/resources/project_iam_member) | resource |
23+
| [google_project_iam_member.serviceusage_admin](https://registry.terraform.io/providers/hashicorp/google/6.12.0/docs/resources/project_iam_member) | resource |
24+
| [google_project_service.billingbudgets](https://registry.terraform.io/providers/hashicorp/google/6.12.0/docs/resources/project_service) | resource |
25+
| [google_service_account.backplane](https://registry.terraform.io/providers/hashicorp/google/6.12.0/docs/resources/service_account) | resource |
26+
| [google_service_account_key.backplane](https://registry.terraform.io/providers/hashicorp/google/6.12.0/docs/resources/service_account_key) | resource |
27+
| [google_project.backplane](https://registry.terraform.io/providers/hashicorp/google/6.12.0/docs/data-sources/project) | data source |
28+
29+
## Inputs
30+
31+
| Name | Description | Type | Default | Required |
32+
|------|-------------|------|---------|:--------:|
33+
| <a name="input_backplane_project_id"></a> [backplane\_project\_id](#input\_backplane\_project\_id) | The project hosting the building block backplane resources | `string` | n/a | yes |
34+
| <a name="input_backplane_service_account_name"></a> [backplane\_service\_account\_name](#input\_backplane\_service\_account\_name) | The name of the service account to be created for the backplane | `string` | `"building-block-budget-alert"` | no |
35+
| <a name="input_billing_account_id"></a> [billing\_account\_id](#input\_billing\_account\_id) | The billing account ID where budget permissions will be granted | `string` | n/a | yes |
36+
37+
## Outputs
38+
39+
| Name | Description |
40+
|------|-------------|
41+
| <a name="output_backplane_project_id"></a> [backplane\_project\_id](#output\_backplane\_project\_id) | The project hosting the building block backplane resources |
42+
| <a name="output_billing_account_id"></a> [billing\_account\_id](#output\_billing\_account\_id) | The billing account ID where budget permissions were granted |
43+
| <a name="output_credentials_json"></a> [credentials\_json](#output\_credentials\_json) | The JSON credentials for the backplane service account |
44+
| <a name="output_service_account_email"></a> [service\_account\_email](#output\_service\_account\_email) | Email address of the backplane service account |
45+
| <a name="output_service_account_id"></a> [service\_account\_id](#output\_service\_account\_id) | ID of the backplane service account |
46+
<!-- END_TF_DOCS -->
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
data "google_project" "backplane" {
2+
project_id = var.backplane_project_id
3+
}
4+
5+
resource "google_service_account" "backplane" {
6+
project = data.google_project.backplane.project_id
7+
account_id = var.backplane_service_account_name
8+
display_name = var.backplane_service_account_name
9+
}
10+
11+
# Grant billing account permissions to create budgets
12+
resource "google_billing_account_iam_member" "budget_admin" {
13+
billing_account_id = var.billing_account_id
14+
role = "roles/billing.costsManager"
15+
member = "serviceAccount:${google_service_account.backplane.email}"
16+
}
17+
18+
# Additional permission to view billing data
19+
resource "google_billing_account_iam_member" "billing_viewer" {
20+
billing_account_id = var.billing_account_id
21+
role = "roles/billing.viewer"
22+
member = "serviceAccount:${google_service_account.backplane.email}"
23+
}
24+
25+
resource "google_service_account_key" "backplane" {
26+
service_account_id = google_service_account.backplane.name
27+
}
28+
29+
resource "google_project_iam_member" "notification_channel_admin" {
30+
project = data.google_project.backplane.project_id
31+
role = "roles/monitoring.notificationChannelEditor"
32+
member = "serviceAccount:${google_service_account.backplane.email}"
33+
}
34+
35+
resource "google_project_iam_member" "serviceusage_admin" {
36+
project = data.google_project.backplane.project_id
37+
role = "roles/serviceusage.serviceUsageAdmin"
38+
member = "serviceAccount:${google_service_account.backplane.email}"
39+
}
40+
41+
resource "google_project_service" "billingbudgets" {
42+
project = data.google_project.backplane.project_id
43+
service = "billingbudgets.googleapis.com"
44+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
output "service_account_email" {
2+
description = "Email address of the backplane service account"
3+
value = google_service_account.backplane.email
4+
}
5+
6+
output "service_account_id" {
7+
description = "ID of the backplane service account"
8+
value = google_service_account.backplane.id
9+
}
10+
11+
output "credentials_json" {
12+
description = "The JSON credentials for the backplane service account"
13+
value = base64decode(google_service_account_key.backplane.private_key)
14+
sensitive = true
15+
}
16+
17+
output "billing_account_id" {
18+
description = "The billing account ID where budget permissions were granted"
19+
value = var.billing_account_id
20+
}
21+
22+
output "backplane_project_id" {
23+
description = "The project hosting the building block backplane resources"
24+
value = data.google_project.backplane.project_id
25+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
variable "backplane_project_id" {
3+
type = string
4+
description = "The project hosting the building block backplane resources"
5+
}
6+
7+
variable "billing_account_id" {
8+
type = string
9+
description = "The billing account ID where budget permissions will be granted"
10+
}
11+
12+
variable "backplane_service_account_name" {
13+
type = string
14+
description = "The name of the service account to be created for the backplane"
15+
default = "building-block-budget-alert"
16+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
terraform {
2+
required_providers {
3+
google = {
4+
source = "hashicorp/google"
5+
version = "6.12.0"
6+
}
7+
}
8+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
This building block sets up a GCP budget alert on your account and is intended for teams managing GCP workloads who want to avoid accidental overspending by proactively monitoring cloud costs.
2+
3+
## 🚀 Usage Example
4+
5+
A development team sets up a GCP budget alert to **receive notifications** when their monthly GCP spend exceeds 80% of their allocated budget.
6+
7+
You can customize when alerts are triggered by providing a YAML string to the `alert_thresholds_yaml` input variable. Each entry specifies a percentage threshold and whether it applies to actual or forecasted spend.
8+
9+
**Example input:**
10+
```yaml
11+
- percent: 80
12+
basis: ACTUAL
13+
- percent: 100
14+
basis: FORECASTED
15+
```
16+
17+
- `percent`: The percentage of the budget that will trigger an alert (e.g., `80` for 80%).
18+
- `basis`: Whether the alert is based on `ACTUAL` spend or `FORECASTED` spend.
19+
20+
This allows you to receive notifications both when your actual spend reaches a certain threshold and when your forecasted spend is projected to exceed your budget.
21+
22+
## 🔄 Shared Responsibility
23+
24+
| Responsibility | Platform Team ✅ | Application Team ✅/❌ |
25+
|----------------------|----------------|------------------|
26+
| Provides automation for GCP Budget setup | ✅ | ❌ |
27+
| Manages alert delivery mechanism (e.g., Pub/Sub, email) | ✅ | ❌ |
28+
| Defines the budget threshold | ❌ | ✅ |
29+
| Adjusts alerts based on cost trends | ❌ | ✅ |
30+
31+
## 💡 Best Practices for Choosing a Budget Threshold
32+
To set an effective budget alert:
33+
- Start with **historical GCP spend** as a baseline.
34+
- Set alerts at **80% and 95% of the budget** to allow for proactive adjustments.
35+
- Consider **seasonal or usage-based variations** in cloud costs.
36+
- Use **multiple alerts** (e.g., per service, per team) if necessary to get granular insights.
37+
38+
---
39+
Would you like to include specific details about notification methods (e.g., email, Slack, Pub/Sub, etc.) or tie this into your overall cloud governance policies? Let me know if you want refinements! 🚀
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
name: GCP Project Budget Alert
3+
supportedPlatforms:
4+
- gcp
5+
description: |
6+
Sets up budget alerts for a GCP project to monitor spending and prevent cost overruns.
7+
---
8+
9+
This buildingblock deploys a GCP budget alert to monitor project spending and send notifications when budget thresholds are exceeded.
10+
11+
## Permissions
12+
13+
Please reference the [backplane implementation](../backplane/) for the required permissions to deploy this building block.
14+
15+
<!-- BEGIN_TF_DOCS -->
16+
## Requirements
17+
18+
| Name | Version |
19+
|------|---------|
20+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
21+
| <a name="requirement_google"></a> [google](#requirement\_google) | 6.12.0 |
22+
23+
## Modules
24+
25+
No modules.
26+
27+
## Resources
28+
29+
| Name | Type |
30+
|------|------|
31+
| [google_billing_budget.budget](https://registry.terraform.io/providers/hashicorp/google/6.12.0/docs/resources/billing_budget) | resource |
32+
| [google_monitoring_notification_channel.notification_channel](https://registry.terraform.io/providers/hashicorp/google/6.12.0/docs/resources/monitoring_notification_channel) | resource |
33+
34+
## Inputs
35+
36+
| Name | Description | Type | Default | Required |
37+
|------|-------------|------|---------|:--------:|
38+
| <a name="input_alert_thresholds_yaml"></a> [alert\_thresholds\_yaml](#input\_alert\_thresholds\_yaml) | YAML string defining alert thresholds as a list of objects having fields 'percent' and 'basis' | `string` | `"- percent: 80\n basis: ACTUAL\n- percent: 100\n basis: FORECASTED\n"` | no |
39+
| <a name="input_backplane_project_id"></a> [backplane\_project\_id](#input\_backplane\_project\_id) | The project ID where the backplane resources will be created | `string` | n/a | yes |
40+
| <a name="input_billing_account_id"></a> [billing\_account\_id](#input\_billing\_account\_id) | The ID of the billing account to which the budget will be applied | `string` | n/a | yes |
41+
| <a name="input_budget_currency"></a> [budget\_currency](#input\_budget\_currency) | The currency for the budget amount, e.g., EUR | `string` | `"EUR"` | no |
42+
| <a name="input_budget_name"></a> [budget\_name](#input\_budget\_name) | Display name for the budget | `string` | n/a | yes |
43+
| <a name="input_contact_email"></a> [contact\_email](#input\_contact\_email) | email address to receive budget alerts | `string` | n/a | yes |
44+
| <a name="input_monthly_budget_amount"></a> [monthly\_budget\_amount](#input\_monthly\_budget\_amount) | The budget amount in the project's billing currency | `number` | n/a | yes |
45+
| <a name="input_project_id"></a> [project\_id](#input\_project\_id) | The GCP project ID where the budget will be created | `string` | n/a | yes |
46+
47+
## Outputs
48+
49+
| Name | Description |
50+
|------|-------------|
51+
| <a name="output_budget_id"></a> [budget\_id](#output\_budget\_id) | The ID of the created budget |
52+
<!-- END_TF_DOCS -->
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
run "verify" {
2+
variables {
3+
budget_name = "integrationtest"
4+
contact_email = "[email protected]"
5+
monthly_budget_amount = 100
6+
}
7+
8+
assert {
9+
condition = output.budget_id != null
10+
error_message = "did not produce a budget id"
11+
}
12+
}

0 commit comments

Comments
 (0)