diff --git a/infrastructure/modules/key-vault/alerts.tf b/infrastructure/modules/key-vault/alerts.tf
index 2f0200ee..623c2380 100644
--- a/infrastructure/modules/key-vault/alerts.tf
+++ b/infrastructure/modules/key-vault/alerts.tf
@@ -95,3 +95,101 @@ QUERY
]
}
}
+
+resource "azurerm_monitor_scheduled_query_rules_alert_v2" "kv_certificate_near_expiry" {
+ count = var.enable_alerting == true ? 1 : 0
+
+ name = "${azurerm_key_vault.keyvault.name}-certificate-near-expiry"
+ resource_group_name = var.resource_group_name_monitoring != null ? var.resource_group_name_monitoring : var.resource_group_name
+ location = var.location
+
+ evaluation_frequency = var.certificate_near_expiry_alert.evaluation_frequency
+ window_duration = var.certificate_near_expiry_alert.window_duration
+ scopes = [azurerm_key_vault.keyvault.id]
+ severity = 2
+
+ criteria {
+ query = <<-QUERY
+AzureDiagnostics
+| where ResourceProvider == "MICROSOFT.KEYVAULT"
+| where OperationName contains "CertificateNearExpiry"
+| project
+ CertificateName = column_ifexists("eventGridEventProperties_data_ObjectName_s","")
+| summarize Events=count() by CertificateName
+QUERY
+
+ time_aggregation_method = "Total"
+ threshold = var.certificate_near_expiry_alert.threshold
+ operator = "GreaterThanOrEqual"
+
+ resource_id_column = "CertificateName"
+ metric_measure_column = "Events"
+
+ dimension {
+ name = "CertificateName"
+ operator = "Include"
+ values = ["*"]
+ }
+ }
+
+ description = "The Key Vault certificate is nearing expiration."
+
+ action {
+ action_groups = [var.action_group_id]
+ }
+
+ lifecycle {
+ ignore_changes = [
+ tags
+ ]
+ }
+}
+
+resource "azurerm_monitor_scheduled_query_rules_alert_v2" "kv_certificate_expired" {
+ count = var.enable_alerting == true ? 1 : 0
+
+ name = "${azurerm_key_vault.keyvault.name}-certificate-expired"
+ resource_group_name = var.resource_group_name_monitoring != null ? var.resource_group_name_monitoring : var.resource_group_name
+ location = var.location
+
+ evaluation_frequency = var.certificate_expired_alert.evaluation_frequency
+ window_duration = var.certificate_expired_alert.window_duration
+ scopes = [azurerm_key_vault.keyvault.id]
+ severity = 2
+
+ criteria {
+ query = <<-QUERY
+AzureDiagnostics
+| where ResourceProvider == "MICROSOFT.KEYVAULT"
+| where OperationName contains "CertificateExpired"
+| project
+ CertificateName = column_ifexists("eventGridEventProperties_data_ObjectName_s","")
+| summarize Events=count() by CertificateName
+QUERY
+
+ time_aggregation_method = "Total"
+ threshold = var.certificate_expired_alert.threshold
+ operator = "GreaterThanOrEqual"
+
+ resource_id_column = "CertificateName"
+ metric_measure_column = "Events"
+
+ dimension {
+ name = "CertificateName"
+ operator = "Include"
+ values = ["*"]
+ }
+ }
+
+ description = "The Key Vault certificate has expired."
+
+ action {
+ action_groups = [var.action_group_id]
+ }
+
+ lifecycle {
+ ignore_changes = [
+ tags
+ ]
+ }
+}
diff --git a/infrastructure/modules/key-vault/tfdocs.md b/infrastructure/modules/key-vault/tfdocs.md
index 8dd88bd2..0bb170a1 100644
--- a/infrastructure/modules/key-vault/tfdocs.md
+++ b/infrastructure/modules/key-vault/tfdocs.md
@@ -184,6 +184,34 @@ object({
})
```
+### [certificate\_near\_expiry\_alert](#input\_certificate\_near\_expiry\_alert)
+
+Description: Configuration for the Key Vault certificate near expiry alert.
+
+Type:
+
+```hcl
+object({
+ evaluation_frequency = string
+ window_duration = string
+ threshold = number
+})
+```
+
+### [secret\_certificate\_alert](#input\_certificate\_expired\_alert)
+
+Description: Configuration for the Key Vault certificate expired alert.
+
+Type:
+
+```hcl
+object({
+ evaluation_frequency = string
+ window_duration = string
+ threshold = number
+})
+```
+
## Modules
The following Modules are called:
diff --git a/infrastructure/modules/key-vault/variables.tf b/infrastructure/modules/key-vault/variables.tf
index 36e3e690..0ce79d0e 100644
--- a/infrastructure/modules/key-vault/variables.tf
+++ b/infrastructure/modules/key-vault/variables.tf
@@ -105,6 +105,54 @@ variable "secret_expired_alert" {
}
}
+variable "certificate_near_expiry_alert" {
+ type = object({
+ evaluation_frequency = string
+ window_duration = string
+ threshold = number
+ })
+
+ validation {
+ condition = contains(
+ ["PT1M", "PT5M", "PT15M", "PT30M", "PT1H", "PT6H", "PT12H", "P1D"],
+ var.certificate_near_expiry_alert.evaluation_frequency
+ )
+ error_message = "certificate_near_expiry_alert.evaluation_frequency must be one of: PT1M, PT5M, PT15M, PT30M, PT1H, PT6H, PT12H, P1D"
+ }
+
+ validation {
+ condition = contains(
+ ["PT1M", "PT5M", "PT15M", "PT30M", "PT1H", "PT6H", "PT12H", "P1D"],
+ var.certificate_near_expiry_alert.window_duration
+ )
+ error_message = "certificate_near_expiry_alert.window_duration must be one of: PT1M, PT5M, PT15M, PT30M, PT1H, PT6H, PT12H, P1D"
+ }
+}
+
+variable "certificate_expired_alert" {
+ type = object({
+ evaluation_frequency = string
+ window_duration = string
+ threshold = number
+ })
+
+ validation {
+ condition = contains(
+ ["PT1M", "PT5M", "PT15M", "PT30M", "PT1H", "PT6H", "PT12H", "P1D"],
+ var.certificate_expired_alert.evaluation_frequency
+ )
+ error_message = "certificate_expired_alert.evaluation_frequency must be one of: PT1M, PT5M, PT15M, PT30M, PT1H, PT6H, PT12H, P1D"
+ }
+
+ validation {
+ condition = contains(
+ ["PT1M", "PT5M", "PT15M", "PT30M", "PT1H", "PT6H", "PT12H", "P1D"],
+ var.certificate_expired_alert.window_duration
+ )
+ error_message = "certificate_expired_alert.window_duration must be one of: PT1M, PT5M, PT15M, PT30M, PT1H, PT6H, PT12H, P1D"
+ }
+}
+
variable "name" {
description = "The name of the Key Vault."
type = string