Skip to content

Commit f60e8d5

Browse files
committed
feat: implemented alerting for expiring certificates for application gateway
1 parent 51ab3ef commit f60e8d5

4 files changed

Lines changed: 189 additions & 18 deletions

File tree

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
resource "azurerm_monitor_metric_alert" "this" {
2+
name = "${var.name}-availability-alert"
3+
resource_group_name = var.resource_group_name
4+
5+
scopes = [azurerm_application_insights_standard_web_test.this.id, var.application_insights_id]
6+
severity = 0
7+
8+
frequency = var.alert.frequency
9+
window_size = var.alert.window_size
10+
auto_mitigate = var.alert.auto_mitigate
11+
12+
application_insights_web_test_location_availability_criteria {
13+
web_test_id = azurerm_application_insights_standard_web_test.this.id
14+
component_id = var.application_insights_id
15+
failed_location_count = 2
16+
}
17+
18+
description = var.alert.description
19+
20+
action {
21+
action_group_id = var.action_group_id
22+
}
23+
}

infrastructure/modules/application-insights-availability-test/main.tf

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,27 @@ resource "azurerm_application_insights_standard_web_test" "this" {
1010
enabled = true
1111

1212
request {
13-
url = var.target_url
14-
}
15-
16-
geo_locations = var.geo_locations
17-
}
13+
url = var.target_url
14+
http_verb = var.http_verb
1815

19-
resource "azurerm_monitor_metric_alert" "this" {
20-
name = "${var.name}-availability-alert"
21-
resource_group_name = var.resource_group_name
22-
scopes = [azurerm_application_insights_standard_web_test.this.id, var.application_insights_id]
23-
description = "availability test alert"
24-
severity = 0
25-
26-
application_insights_web_test_location_availability_criteria {
27-
web_test_id = azurerm_application_insights_standard_web_test.this.id
28-
component_id = var.application_insights_id
29-
failed_location_count = 2
16+
dynamic "header" {
17+
for_each = var.headers
18+
content {
19+
name = header.key
20+
value = header.value
21+
}
22+
}
3023
}
3124

32-
action {
33-
action_group_id = var.action_group_id
25+
# SSL validation rules
26+
dynamic "validation_rules" {
27+
for_each = try(var.ssl_validation.enabled, false) ? [1] : []
28+
content {
29+
expected_status_code = var.ssl_validation.expected_status_code
30+
ssl_check_enabled = var.ssl_validation.ssl_check_enabled
31+
ssl_cert_remaining_lifetime = var.ssl_validation.ssl_cert_remaining_lifetime
32+
}
3433
}
34+
35+
geo_locations = var.geo_locations
3536
}

infrastructure/modules/application-insights-availability-test/tfdocs.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,63 @@ Type: `number`
7878

7979
Default: `30`
8080

81+
### <a name="input_http_verb"></a> [http_verb](#input\_http\_verb)
82+
83+
Description: The HTTP verb used for the request.
84+
85+
Type: `string`
86+
87+
Allowed values: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
88+
89+
Default: GET
90+
91+
### <a name="input_headers"></a> [headers](#input\_headers)
92+
93+
Description: A map of HTTP request headers (name => value).
94+
95+
Type: `map(string)`
96+
97+
Default: {}
98+
99+
### <a name="input_ssl_validation"></a> [ssl_validation](#input\_ssl\_validation)
100+
101+
Description: SSL validation configuration for the availability test. Set `enabled = false` to omit SSL validation completely.
102+
103+
Type:
104+
```hcl
105+
object({
106+
enabled = optional(bool, false)
107+
expected_status_code = optional(number, null)
108+
ssl_check_enabled = optional(bool, true)
109+
ssl_cert_remaining_lifetime = optional(number, null)
110+
})
111+
```
112+
113+
Default: null
114+
115+
Validations:
116+
- expected_status_code must be 0 ('0' means 'response code < 400') or a valid HTTP status code (100–599)
117+
- ssl_cert_remaining_lifetime must be null or between 1–365
118+
119+
### <a name="input_alert"></a> [alert](#input\_alert)
120+
121+
Description: Configuration for the availability alert rule.
122+
123+
Type:
124+
```hcl
125+
object({
126+
description = optional(string, "Availability test alert")
127+
frequency = optional(string, "PT1M")
128+
window_size = optional(string, "PT5M")
129+
auto_mitigate = optional(bool, true)
130+
})
131+
```
132+
133+
Defaults: {}
134+
135+
Validations:
136+
- frequency must be one of: PT1M, PT5M, PT15M, PT30M, PT1H
137+
- window_size must be one of: PT1M, PT5M, PT15M, PT30M, PT1H, PT6H, PT12H, P1D
81138

82139
## Resources
83140

infrastructure/modules/application-insights-availability-test/variables.tf

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,93 @@ variable "target_url" {
5454
type = string
5555
description = "The target URL for the restful endpoint to hit to validate the application is available"
5656
}
57+
58+
variable "http_verb" {
59+
description = "HTTP verb (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS)"
60+
type = string
61+
default = "GET"
62+
validation {
63+
condition = contains(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"], var.http_verb)
64+
error_message = "http_verb must be one of GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS."
65+
}
66+
}
67+
68+
variable "headers" {
69+
description = "Map of request headers to send (name => value)"
70+
type = map(string)
71+
default = {}
72+
}
73+
74+
variable "ssl_validation" {
75+
description = <<EOT
76+
The SSL validation settings for the standard web test.
77+
78+
Set `enabled = false` to omit the SSL validation block entirely.
79+
If you want to validate response body text, set content's match to a non-null string.
80+
EOT
81+
type = object({
82+
enabled = optional(bool, false)
83+
expected_status_code = optional(number, null)
84+
ssl_check_enabled = optional(bool, true)
85+
ssl_cert_remaining_lifetime = optional(number, null)
86+
})
87+
88+
validation {
89+
condition = (
90+
var.ssl_validation == null ||
91+
try(var.ssl_validation.expected_status_code, 0) == 0 ||
92+
(try(var.ssl_validation.expected_status_code, 0) >= 100 &&
93+
try(var.ssl_validation.expected_status_code, 0) < 600)
94+
)
95+
error_message = "The expected status code must be 0 ('0' means 'response code < 400') or a valid HTTP status code between 100 and 599."
96+
}
97+
98+
validation {
99+
condition = (
100+
var.ssl_validation == null ||
101+
try(var.ssl_validation.ssl_cert_remaining_lifetime, null) == null ||
102+
(try(var.ssl_validation.ssl_cert_remaining_lifetime, 0) >= 1 &&
103+
try(var.ssl_validation.ssl_cert_remaining_lifetime, 0) <= 365)
104+
)
105+
error_message = "The SSL certificate remaining lifetime must be null or an integer between 1 and 365."
106+
}
107+
108+
validation {
109+
condition = (
110+
var.ssl_validation == null ||
111+
try(var.ssl_validation.enabled, false) == false ||
112+
true
113+
)
114+
error_message = "When enabled = false, other SSL fields are ignored."
115+
}
116+
117+
default = null
118+
nullable = true
119+
}
120+
121+
variable "alert" {
122+
type = object({
123+
description = optional(string, "Availability test alert")
124+
frequency = optional(string, "PT1M")
125+
window_size = optional(string, "PT5M")
126+
auto_mitigate = optional(bool, true)
127+
})
128+
129+
validation {
130+
condition = contains(
131+
["PT1M", "PT5M", "PT15M", "PT30M", "PT1H"],
132+
var.alert.frequency
133+
)
134+
error_message = "Frequency must be one of: PT1M, PT5M, PT15M, PT30M, PT1H"
135+
}
136+
137+
validation {
138+
condition = contains(
139+
["PT1M", "PT5M", "PT15M", "PT30M", "PT1H", "PT6H", "PT12H", "P1D"],
140+
var.alert.window_size
141+
)
142+
error_message = "Window size must be one of: PT1M, PT5M, PT15M, PT30M, PT1H, PT6H, PT12H, P1D"
143+
}
144+
145+
default = {}
146+
}

0 commit comments

Comments
 (0)