diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml
index e8743405..584462af 100644
--- a/.github/workflows/documentation.yaml
+++ b/.github/workflows/documentation.yaml
@@ -11,6 +11,7 @@ jobs:
fail-fast: false
matrix:
module:
+ - audit-serviceaccount
- authorize-private-service
- bucket-events
- cloudevent-broker
diff --git a/modules/audit-serviceaccount/README.md b/modules/audit-serviceaccount/README.md
new file mode 100644
index 00000000..e8f9dfa4
--- /dev/null
+++ b/modules/audit-serviceaccount/README.md
@@ -0,0 +1,73 @@
+# `audit-serviceaccount`
+
+This module creates an alert policy to monitor the principals that are
+generating tokens for a particular service account.
+
+The set of authorized principals can be enumerated explicitly:
+```hcl
+module "audit-foo-usage" {
+ source = "chainguard-dev/common/infra//modules/audit-serviceaccount"
+
+ project_id = var.project_id
+ service-account = google_service_account.foo.email
+
+ allowed_principals = [
+ # Only GKE should generate tokens for this service account.
+ "serviceAccount:${var.project_id}.svc.id.goog[foo-system/foo]",
+ ]
+
+ notification_channels = var.notification_channels
+}
+```
+
+Or a regular expression can be provided for the allowed principals:
+```hcl
+module "audit-foo-usage" {
+ source = "chainguard-dev/common/infra//modules/audit-serviceaccount"
+
+ project_id = var.project_id
+ service-account = google_service_account.foo.email
+
+ # Match v1.2.3 style tags on this repository.
+ allowed_principal_regex = "principal://iam[.]googleapis[.]com/${google_iam_workload_identity_pool.pool.name}/subject/repo:chainguard-dev/terraform-infra-common:ref:refs/tags/v[0-9]+[.][0-9]+[.][0-9]+"
+
+ notification_channels = var.notification_channels
+}
+```
+
+
+
+## Requirements
+
+No requirements.
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [google](#provider\_google) | n/a |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [google_monitoring_alert_policy.generate-access-token](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/monitoring_alert_policy) | resource |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [allowed\_principal\_regex](#input\_allowed\_principal\_regex) | A regular expression to match allowed principals. | `string` | `""` | no |
+| [allowed\_principals](#input\_allowed\_principals) | The list of principals authorized to assume this identity. | `list(string)` | `[]` | no |
+| [notification\_channels](#input\_notification\_channels) | The list of notification channels to alert when this policy fires. | `list(string)` | n/a | yes |
+| [project\_id](#input\_project\_id) | n/a | `string` | n/a | yes |
+| [service-account](#input\_service-account) | The email of the service account being audited. | `string` | n/a | yes |
+
+## Outputs
+
+No outputs.
+
diff --git a/modules/audit-serviceaccount/main.tf b/modules/audit-serviceaccount/main.tf
new file mode 100644
index 00000000..cbb75ffd
--- /dev/null
+++ b/modules/audit-serviceaccount/main.tf
@@ -0,0 +1,43 @@
+resource "google_monitoring_alert_policy" "generate-access-token" {
+ count = length(var.notification_channels) > 0 ? 1 : 0
+
+ # In the absence of data, incident will auto-close after an hour
+ alert_strategy {
+ auto_close = "3600s"
+
+ notification_rate_limit {
+ period = "3600s" // re-alert hourly if condition still valid.
+ }
+ }
+
+ display_name = "Abnormal Access Token Generation: ${var.service-account}"
+ combiner = "OR"
+
+ conditions {
+ display_name = "Access Token Generation"
+
+ condition_matched_log {
+ filter = < [audit-delivery-serviceaccount](#module\_audit-delivery-serviceaccount) | ../audit-serviceaccount | n/a |
| [authorize-delivery](#module\_authorize-delivery) | ../authorize-private-service | n/a |
| [http](#module\_http) | ../dashboard/sections/http | n/a |
| [layout](#module\_layout) | ../dashboard/sections/layout | n/a |
diff --git a/modules/bucket-events/main.tf b/modules/bucket-events/main.tf
index f8f621e5..77ae5e9c 100644
--- a/modules/bucket-events/main.tf
+++ b/modules/bucket-events/main.tf
@@ -55,6 +55,22 @@ resource "google_service_account_iam_binding" "allow-pubsub-to-mint-tokens" {
members = ["serviceAccount:${google_project_service_identity.pubsub.email}"]
}
+module "audit-delivery-serviceaccount" {
+ count = length(var.notification_channels) > 0 ? 1 : 0
+
+ source = "../audit-serviceaccount"
+
+ project_id = var.project_id
+ service-account = google_service_account.delivery.email
+
+ # The absence of authorized identities here means that
+ # nothing is authorized to act as this service account.
+ # Note: Cloud Pub/Sub's usage doesn't show up in the
+ # audit logs.
+
+ notification_channels = var.notification_channels
+}
+
module "this" {
source = "../regional-go-service"
project_id = var.project_id
diff --git a/modules/cloudevent-recorder/README.md b/modules/cloudevent-recorder/README.md
index 02f94a39..ed76be57 100644
--- a/modules/cloudevent-recorder/README.md
+++ b/modules/cloudevent-recorder/README.md
@@ -93,6 +93,7 @@ No requirements.
| Name | Source | Version |
|------|--------|---------|
+| [audit-import-serviceaccount](#module\_audit-import-serviceaccount) | ../audit-serviceaccount | n/a |
| [recorder-dashboard](#module\_recorder-dashboard) | ../dashboard/cloudevent-receiver | n/a |
| [this](#module\_this) | ../regional-go-service | n/a |
| [triggers](#module\_triggers) | ../cloudevent-trigger | n/a |
@@ -107,6 +108,7 @@ No requirements.
| [google_bigquery_table.types](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/bigquery_table) | resource |
| [google_bigquery_table_iam_binding.import-writes-to-tables](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/bigquery_table_iam_binding) | resource |
| [google_monitoring_alert_policy.bq_dts](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/monitoring_alert_policy) | resource |
+| [google_monitoring_alert_policy.bucket-access](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/monitoring_alert_policy) | resource |
| [google_pubsub_subscription.dead-letter-pull-sub](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/pubsub_subscription) | resource |
| [google_pubsub_subscription.this](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/pubsub_subscription) | resource |
| [google_pubsub_subscription_iam_binding.allow-pubsub-to-ack](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/pubsub_subscription_iam_binding) | resource |
diff --git a/modules/cloudevent-recorder/bigquery.tf b/modules/cloudevent-recorder/bigquery.tf
index 64a3b212..c2b85b7c 100644
--- a/modules/cloudevent-recorder/bigquery.tf
+++ b/modules/cloudevent-recorder/bigquery.tf
@@ -74,6 +74,22 @@ resource "google_service_account_iam_binding" "provisioner-acts-as-import-identi
members = [var.provisioner]
}
+module "audit-import-serviceaccount" {
+ count = length(var.notification_channels) > 0 ? 1 : 0
+
+ source = "../audit-serviceaccount"
+
+ project_id = var.project_id
+ service-account = google_service_account.import-identity.email
+
+ # The absence of authorized identities here means that
+ # nothing is authorized to act as this service account.
+ # Note: BigQuery DTS's usage doesn't show up in the
+ # audit logs.
+
+ notification_channels = var.notification_channels
+}
+
// Create a BQ DTS job for each of the regions x types pulling from the appropriate buckets and paths.
resource "google_bigquery_data_transfer_config" "import-job" {
for_each = local.regional-types
diff --git a/modules/cloudevent-recorder/main.tf b/modules/cloudevent-recorder/main.tf
index 4dbf9938..645d0129 100644
--- a/modules/cloudevent-recorder/main.tf
+++ b/modules/cloudevent-recorder/main.tf
@@ -50,3 +50,70 @@ resource "google_storage_bucket" "recorder" {
// What identity is deploying this?
data "google_client_openid_userinfo" "me" {}
+resource "google_monitoring_alert_policy" "bucket-access" {
+ count = length(var.notification_channels) > 0 ? 1 : 0
+
+ # In the absence of data, incident will auto-close after an hour
+ alert_strategy {
+ auto_close = "3600s"
+
+ notification_rate_limit {
+ period = "3600s" // re-alert hourly if condition still valid.
+ }
+ }
+
+ display_name = "Abnormal Event Bucket Access: ${var.name}"
+ combiner = "OR"
+
+ conditions {
+ display_name = "Bucket Access"
+
+ condition_matched_log {
+ filter = < [audit-trigger-serviceaccount](#module\_audit-trigger-serviceaccount) | ../audit-serviceaccount | n/a |
| [authorize-delivery](#module\_authorize-delivery) | ../authorize-private-service | n/a |
## Resources
diff --git a/modules/cloudevent-trigger/main.tf b/modules/cloudevent-trigger/main.tf
index c0dd607b..a79115c7 100644
--- a/modules/cloudevent-trigger/main.tf
+++ b/modules/cloudevent-trigger/main.tf
@@ -30,6 +30,22 @@ resource "google_service_account_iam_binding" "allow-pubsub-to-mint-tokens" {
members = ["serviceAccount:${google_project_service_identity.pubsub.email}"]
}
+module "audit-trigger-serviceaccount" {
+ count = length(var.notification_channels) > 0 ? 1 : 0
+
+ source = "../audit-serviceaccount"
+
+ project_id = var.project_id
+ service-account = google_service_account.this.email
+
+ # The absence of authorized identities here means that
+ # nothing is authorized to act as this service account.
+ # Note: Cloud Pub/Sub's usage doesn't show up in the
+ # audit logs.
+
+ notification_channels = var.notification_channels
+}
+
// Authorize this service account to invoke the private service receiving
// events from this trigger.
module "authorize-delivery" {
diff --git a/modules/configmap/README.md b/modules/configmap/README.md
index 994bf245..2c845283 100644
--- a/modules/configmap/README.md
+++ b/modules/configmap/README.md
@@ -22,7 +22,7 @@ module "my-configmap" {
EOT
# Optionally: channels to notify if this configuration is manipulated.
- notification-channels = [ ... ]
+ notification_channels = [ ... ]
}
module "foo-service" {
@@ -77,6 +77,7 @@ No modules.
| Name | Type |
|------|------|
+| [google_monitoring_alert_policy.anomalous-secret-access](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/monitoring_alert_policy) | resource |
| [google_secret_manager_secret.this](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/secret_manager_secret) | resource |
| [google_secret_manager_secret_iam_binding.authorize-access](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/secret_manager_secret_iam_binding) | resource |
| [google_secret_manager_secret_version.data](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/secret_manager_secret_version) | resource |
@@ -89,7 +90,7 @@ No modules.
|------|-------------|------|---------|:--------:|
| [data](#input\_data) | The data to place in the secret. | `string` | n/a | yes |
| [name](#input\_name) | The name to give the secret. | `string` | n/a | yes |
-| [notification-channels](#input\_notification-channels) | The channels to notify if the configuration data is improperly accessed. | `list(string)` | n/a | yes |
+| [notification\_channels](#input\_notification\_channels) | The channels to notify if the configuration data is improperly accessed. | `list(string)` | n/a | yes |
| [project\_id](#input\_project\_id) | n/a | `string` | n/a | yes |
| [service-account](#input\_service-account) | The email of the service account that will access the secret. | `string` | n/a | yes |
diff --git a/modules/configmap/main.tf b/modules/configmap/main.tf
index a91e401c..79481eee 100644
--- a/modules/configmap/main.tf
+++ b/modules/configmap/main.tf
@@ -28,3 +28,57 @@ data "google_project" "project" { project_id = var.project_id }
// What identity is deploying this?
data "google_client_openid_userinfo" "me" {}
+// Create an alert policy to notify if the secret is accessed by an unauthorized entity.
+resource "google_monitoring_alert_policy" "anomalous-secret-access" {
+ count = length(var.notification_channels) > 0 ? 1 : 0
+
+ # In the absence of data, incident will auto-close after an hour
+ alert_strategy {
+ auto_close = "3600s"
+
+ notification_rate_limit {
+ period = "3600s" // re-alert hourly if condition still valid.
+ }
+ }
+
+ display_name = "Abnormal ConfigMap Access: ${var.name}"
+ combiner = "OR"
+
+ conditions {
+ display_name = "Abnormal ConfigMap Access: ${var.name}"
+
+ condition_matched_log {
+ filter = < [audit-cronjob-serviceaccount](#module\_audit-cronjob-serviceaccount) | ../audit-serviceaccount | n/a |
+| [audit-delivery-serviceaccount](#module\_audit-delivery-serviceaccount) | ../audit-serviceaccount | n/a |
## Resources
@@ -79,6 +82,8 @@ No modules.
| [google-beta_google_cloud_run_v2_job.job](https://registry.terraform.io/providers/hashicorp/google-beta/latest/docs/resources/google_cloud_run_v2_job) | resource |
| [google_cloud_run_v2_job_iam_binding.authorize-calls](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloud_run_v2_job_iam_binding) | resource |
| [google_cloud_scheduler_job.cron](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloud_scheduler_job) | resource |
+| [google_monitoring_alert_policy.anomalous-job-access](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/monitoring_alert_policy) | resource |
+| [google_monitoring_alert_policy.anomalous-job-execution](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/monitoring_alert_policy) | resource |
| [google_monitoring_alert_policy.success](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/monitoring_alert_policy) | resource |
| [google_project_iam_member.authorize-list](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_member) | resource |
| [google_project_iam_member.metrics-writer](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_member) | resource |
diff --git a/modules/cron/main.tf b/modules/cron/main.tf
index 876b735a..3e70d16a 100644
--- a/modules/cron/main.tf
+++ b/modules/cron/main.tf
@@ -18,6 +18,20 @@ resource "google_project_service" "cloudscheduler" {
disable_on_destroy = false
}
+module "audit-cronjob-serviceaccount" {
+ source = "../audit-serviceaccount"
+
+ project_id = var.project_id
+ service-account = var.service_account
+
+ # The absence of authorized identities here means that
+ # nothing is authorized to act as this service account.
+ # Note: Cloud Run's usage doesn't show up in the
+ # audit logs.
+
+ notification_channels = var.notification_channels
+}
+
locals {
repo = var.repository != "" ? var.repository : "gcr.io/${var.project_id}/${var.name}"
}
@@ -203,6 +217,22 @@ resource "google_service_account" "delivery" {
display_name = "Dedicated service account for invoking ${google_cloud_run_v2_job.job.name}."
}
+module "audit-delivery-serviceaccount" {
+ count = length(var.notification_channels) > 0 ? 1 : 0
+
+ source = "../audit-serviceaccount"
+
+ project_id = var.project_id
+ service-account = google_service_account.delivery.email
+
+ # The absence of authorized identities here means that
+ # nothing is authorized to act as this service account.
+ # Note: Cloud Scheduler's usage doesn't show up in the
+ # audit logs.
+
+ notification_channels = var.notification_channels
+}
+
resource "google_cloud_run_v2_job_iam_binding" "authorize-calls" {
project = google_cloud_run_v2_job.job.project
location = google_cloud_run_v2_job.job.location
@@ -252,6 +282,109 @@ data "google_project" "project" { project_id = var.project_id }
// What identity is deploying this?
data "google_client_openid_userinfo" "me" {}
+// Create an alert policy to notify if the job is accessed by an unauthorized entity.
+resource "google_monitoring_alert_policy" "anomalous-job-access" {
+ count = length(var.notification_channels) > 0 ? 1 : 0
+
+ # In the absence of data, incident will auto-close after an hour
+ alert_strategy {
+ auto_close = "3600s"
+
+ notification_rate_limit {
+ period = "3600s" // re-alert hourly if condition still valid.
+ }
+ }
+
+ display_name = "Abnormal CronJob Access: ${var.name}"
+ combiner = "OR"
+
+ conditions {
+ display_name = "Abnormal CronJob Access: ${var.name}"
+
+ condition_matched_log {
+ filter = < [audit-usage](#module\_audit-usage) | ../audit-serviceaccount | n/a |
## Resources
diff --git a/modules/github-gsa/main.tf b/modules/github-gsa/main.tf
index e661e3ad..33547c00 100644
--- a/modules/github-gsa/main.tf
+++ b/modules/github-gsa/main.tf
@@ -132,3 +132,17 @@ resource "google_service_account_iam_binding" "allow-impersonation" {
}
}
}
+
+// Create an auditing policy to ensure that tokens are only issued for identities
+// matching our expectations.
+module "audit-usage" {
+ count = length(var.notification_channels) > 0 ? 1 : 0
+
+ source = "../audit-serviceaccount"
+
+ project_id = var.project_id
+ service-account = google_service_account.this.email
+
+ allowed_principal_regex = local.principalSubject
+ notification_channels = var.notification_channels
+}
diff --git a/modules/regional-go-service/main.tf b/modules/regional-go-service/main.tf
index 068c892e..68f6a8c9 100644
--- a/modules/regional-go-service/main.tf
+++ b/modules/regional-go-service/main.tf
@@ -76,6 +76,11 @@ moved {
to = module.this.google_cloud_run_v2_service.this
}
+moved {
+ from = google_monitoring_alert_policy.anomalous-service-access
+ to = module.this.google_monitoring_alert_policy.anomalous-service-access
+}
+
moved {
from = google_monitoring_alert_policy.bad-rollout
to = module.this.google_monitoring_alert_policy.bad-rollout
diff --git a/modules/regional-service/README.md b/modules/regional-service/README.md
index 1c45d454..d732ef28 100644
--- a/modules/regional-service/README.md
+++ b/modules/regional-service/README.md
@@ -65,7 +65,9 @@ No requirements.
## Modules
-No modules.
+| Name | Source | Version |
+|------|--------|---------|
+| [audit-serviceaccount](#module\_audit-serviceaccount) | ../audit-serviceaccount | n/a |
## Resources
@@ -73,6 +75,7 @@ No modules.
|------|------|
| [google-beta_google_cloud_run_v2_service.this](https://registry.terraform.io/providers/hashicorp/google-beta/latest/docs/resources/google_cloud_run_v2_service) | resource |
| [google_cloud_run_v2_service_iam_member.public-services-are-unauthenticated](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloud_run_v2_service_iam_member) | resource |
+| [google_monitoring_alert_policy.anomalous-service-access](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/monitoring_alert_policy) | resource |
| [google_project_iam_member.metrics-writer](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_member) | resource |
| [google_project_iam_member.profiler-writer](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_member) | resource |
| [google_project_iam_member.trace-writer](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_member) | resource |
diff --git a/modules/regional-service/main.tf b/modules/regional-service/main.tf
index e0b8a0ee..0cb60d94 100644
--- a/modules/regional-service/main.tf
+++ b/modules/regional-service/main.tf
@@ -1,3 +1,18 @@
+module "audit-serviceaccount" {
+ count = length(var.notification_channels) > 0 ? 1 : 0
+
+ source = "../audit-serviceaccount"
+
+ project_id = var.project_id
+ service-account = var.service_account
+
+ # The absence of authorized identities here means that
+ # nothing is authorized to act as this service account.
+ # Note: Cloud Run's usage doesn't show up in the audit logs.
+
+ notification_channels = var.notification_channels
+}
+
resource "google_project_iam_member" "metrics-writer" {
project = var.project_id
role = "roles/monitoring.metricWriter"
@@ -267,6 +282,61 @@ data "google_project" "project" { project_id = var.project_id }
// What identity is deploying this?
data "google_client_openid_userinfo" "me" {}
+// Create an alert policy to notify if the service is accessed by an unauthorized entity.
+resource "google_monitoring_alert_policy" "anomalous-service-access" {
+ count = length(var.notification_channels) > 0 ? 1 : 0
+
+ # In the absence of data, incident will auto-close after an hour
+ alert_strategy {
+ auto_close = "3600s"
+
+ notification_rate_limit {
+ period = "3600s" // re-alert hourly if condition still valid.
+ }
+ }
+
+ display_name = "Abnormal Service Access: ${var.name}"
+ combiner = "OR"
+
+ conditions {
+ display_name = "Abnormal Service Access: ${var.name}"
+
+ condition_matched_log {
+ filter = < [authorized-adder](#input\_authorized-adder) | A member-style representation of the identity authorized to add new secret values (e.g. group:oncall@my-corp.dev). | `string` | n/a | yes |
| [create\_placeholder\_version](#input\_create\_placeholder\_version) | Whether to create a placeholder secret version to avoid bad reference on first deploy. | `bool` | `false` | no |
| [name](#input\_name) | The name to give the secret. | `string` | n/a | yes |
-| [notification-channels](#input\_notification-channels) | The channels to notify if the configuration data is improperly accessed. | `list(string)` | n/a | yes |
+| [notification\_channels](#input\_notification\_channels) | The channels to notify if the configuration data is improperly accessed. | `list(string)` | n/a | yes |
| [project\_id](#input\_project\_id) | n/a | `string` | n/a | yes |
| [service-account](#input\_service-account) | The email of the service account that will access the secret. | `string` | n/a | yes |
diff --git a/modules/secret/main.tf b/modules/secret/main.tf
index 3beb9ff4..c5a5167c 100644
--- a/modules/secret/main.tf
+++ b/modules/secret/main.tf
@@ -41,6 +41,8 @@ data "google_project" "project" { project_id = var.project_id }
// Create an alert policy to notify if the secret is accessed by an unauthorized entity.
resource "google_monitoring_alert_policy" "anomalous-secret-access" {
+ count = length(var.notification_channels) > 0 ? 1 : 0
+
# In the absence of data, incident will auto-close after an hour
alert_strategy {
auto_close = "3600s"
@@ -80,7 +82,7 @@ resource "google_monitoring_alert_policy" "anomalous-secret-access" {
}
}
- notification_channels = var.notification-channels
+ notification_channels = var.notification_channels
enabled = "true"
project = var.project_id
diff --git a/modules/secret/variables.tf b/modules/secret/variables.tf
index 89c6a005..f0df212f 100644
--- a/modules/secret/variables.tf
+++ b/modules/secret/variables.tf
@@ -17,7 +17,7 @@ variable "service-account" {
type = string
}
-variable "notification-channels" {
+variable "notification_channels" {
description = "The channels to notify if the configuration data is improperly accessed."
type = list(string)
}
diff --git a/modules/serverless-gclb/README.md b/modules/serverless-gclb/README.md
index 6daf836b..30696365 100644
--- a/modules/serverless-gclb/README.md
+++ b/modules/serverless-gclb/README.md
@@ -95,6 +95,7 @@ No modules.
| [google_compute_target_https_proxy.public-service](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_target_https_proxy) | resource |
| [google_compute_url_map.public-service](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_url_map) | resource |
| [google_dns_record_set.public-service](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/dns_record_set) | resource |
+| [google_monitoring_alert_policy.abnormal-gclb-access](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/monitoring_alert_policy) | resource |
| [google_client_openid_userinfo.me](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/client_openid_userinfo) | data source |
## Inputs
diff --git a/modules/serverless-gclb/main.tf b/modules/serverless-gclb/main.tf
index 030b395d..d385e35a 100644
--- a/modules/serverless-gclb/main.tf
+++ b/modules/serverless-gclb/main.tf
@@ -165,3 +165,47 @@ locals {
)
}
+resource "google_monitoring_alert_policy" "abnormal-gclb-access" {
+ count = length(var.notification_channels) > 0 ? 1 : 0
+
+ # In the absence of data, incident will auto-close after an hour
+ alert_strategy {
+ auto_close = "3600s"
+
+ notification_rate_limit {
+ period = "3600s" // re-alert hourly if condition still valid.
+ }
+ }
+
+ display_name = "Abnormal GCLB Access"
+ combiner = "OR"
+
+ conditions {
+ display_name = "Anomaly detected"
+
+ condition_matched_log {
+ filter = <