Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions 6_monitoring-management/advisor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Terraform Template - Azure Advisor Alerts (Activity Log)

Costa Rica

[![GitHub](https://img.shields.io/badge/--181717?logo=github&logoColor=ffffff)](https://github.com/)
[brown9804](https://github.com/brown9804)

Last updated: 2026-02-16

------------------------------------------

> This template contains Terraform configurations to create an Action Group and an Activity Log Alert for new Azure Advisor recommendations.

> [!NOTE]
> This is based on the Microsoft Learn quickstart for Advisor alerts.

<img width="650" alt="image" src="https://github.com/user-attachments/assets/98939432-38a0-4f0c-864a-0fe683a000fc" />

## Usage

```sh
az login
terraform init -upgrade
terraform validate
terraform plan
terraform apply -auto-approve
```
139 changes: 139 additions & 0 deletions 6_monitoring-management/advisor/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# main.tf
# Creates an Action Group + Activity Log Alert for new Azure Advisor recommendations.
# Based on Microsoft Learn quickstart: https://learn.microsoft.com/azure/advisor/advisor-alerts-arm

data "azurerm_client_config" "current" {}

resource "azapi_resource" "resource_group" {
type = "Microsoft.Resources/resourceGroups@2022-09-01"
name = var.resource_group_name
location = var.location
parent_id = "/subscriptions/${data.azurerm_client_config.current.subscription_id}"

body = jsonencode({
tags = var.tags
})

response_export_values = [
"id",
"name"
]
}

resource "random_string" "suffix" {
length = var.random_suffix_length
upper = false
special = false
numeric = true

keepers = {
resource_group_name = var.resource_group_name
location = var.location
action_group_base = var.action_group_name
alert_base = var.activity_log_alert_name
email = var.email_address
category = var.recommendation_category
impact = var.recommendation_impact
}
}

locals {
suffix = var.append_random_suffix ? random_string.suffix.result : ""

action_group_name = var.append_random_suffix ? "${var.action_group_name}-${local.suffix}" : var.action_group_name
activity_log_alert_name = var.append_random_suffix ? "${var.activity_log_alert_name}-${local.suffix}" : var.activity_log_alert_name

subscription_scope = "/subscriptions/${data.azurerm_client_config.current.subscription_id}"
alert_scope = (
var.scope_resource_group_name == null
? local.subscription_scope
: "${local.subscription_scope}/resourceGroups/${var.scope_resource_group_name}"
)
}

resource "azapi_resource" "action_group" {
type = "Microsoft.Insights/actionGroups@2019-06-01"
name = local.action_group_name
location = "Global"
parent_id = azapi_resource.resource_group.id

body = jsonencode({
properties = {
groupShortName = var.action_group_short_name
enabled = true
emailReceivers = [
{
name = "email"
emailAddress = var.email_address
}
]
smsReceivers = []
webhookReceivers = []
}
tags = var.tags
})

response_export_values = [
"id",
"name"
]

depends_on = [
azapi_resource.resource_group
]
}

resource "azapi_resource" "advisor_activity_log_alert" {
type = "Microsoft.Insights/activityLogAlerts@2017-04-01"
name = local.activity_log_alert_name
location = "Global"
parent_id = azapi_resource.resource_group.id

body = jsonencode({
properties = {
scopes = [
local.alert_scope
]
condition = {
allOf = [
{
field = "category"
equals = "Recommendation"
},
{
field = "properties.recommendationCategory"
equals = var.recommendation_category
},
{
field = "properties.recommendationImpact"
equals = var.recommendation_impact
},
{
field = "operationName"
equals = "Microsoft.Advisor/recommendations/available/action"
}
]
}
actions = {
actionGroups = [
{
actionGroupId = azapi_resource.action_group.id
webhookProperties = {}
}
]
}
enabled = var.enabled
description = var.description
}
tags = var.tags
})

response_export_values = [
"id",
"name"
]

depends_on = [
azapi_resource.action_group
]
}
14 changes: 14 additions & 0 deletions 6_monitoring-management/advisor/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
output "resource_group_id" {
description = "The resource ID of the Resource Group."
value = azapi_resource.resource_group.id
}

output "action_group_id" {
description = "The resource ID of the Action Group."
value = azapi_resource.action_group.id
}

output "activity_log_alert_id" {
description = "The resource ID of the Activity Log Alert."
value = azapi_resource.advisor_activity_log_alert.id
}
37 changes: 37 additions & 0 deletions 6_monitoring-management/advisor/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# provider.tf

terraform {
required_version = ">= 1.8, < 2.0"

required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.116"
}

azapi = {
source = "Azure/azapi"
version = "~> 1.13"
}

random = {
source = "hashicorp/random"
version = "~> 3.6"
}
}
}

provider "azurerm" {
features {
resource_group {
prevent_deletion_if_contains_resources = false
}
}

# Uses the current Azure CLI context (az login + az account set)
skip_provider_registration = false
}

provider "azapi" {
# Uses the current Azure CLI context (az login + az account set)
}
27 changes: 27 additions & 0 deletions 6_monitoring-management/advisor/terraform.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
resource_group_name = "rg-monitoring-dev-advisor"
location = "eastus"

append_random_suffix = true
random_suffix_length = 6

email_address = "user@domain.com"

action_group_name = "advisorAlert"
action_group_short_name = "advisor"

activity_log_alert_name = "AdvisorAlerts"

recommendation_category = "Cost"
recommendation_impact = "Medium"

# Optional: scope to a specific resource group
# scope_resource_group_name = "rg-some-app-dev"

enabled = true
description = ""

tags = {
env = "dev"
area = "monitoring-management"
iac = "terraform"
}
107 changes: 107 additions & 0 deletions 6_monitoring-management/advisor/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# variables.tf

variable "resource_group_name" {
description = "The name of the Azure Resource Group to deploy into. This template will create the RG if it does not exist (idempotent ARM PUT)."
type = string

validation {
condition = length(trimspace(var.resource_group_name)) > 0
error_message = "resource_group_name must not be empty."
}
}

variable "location" {
description = "The Azure region where the Resource Group will be created (Advisor alerts are global resources but live in a Resource Group)."
type = string

validation {
condition = length(trimspace(var.location)) > 0
error_message = "location must not be empty."
}
}

variable "append_random_suffix" {
description = "Whether to append a random suffix to names to reduce collisions."
type = bool
default = true
}

variable "random_suffix_length" {
description = "Length of the random suffix appended when append_random_suffix is true."
type = number
default = 6

validation {
condition = var.random_suffix_length >= 4 && var.random_suffix_length <= 16
error_message = "random_suffix_length must be between 4 and 16."
}
}

variable "action_group_name" {
description = "Base name of the Action Group. If append_random_suffix is true, the final name will be '<base>-<suffix>'."
type = string
default = "advisorAlert"
}

variable "action_group_short_name" {
description = "Short name for the Action Group (max 12 characters)."
type = string
default = "advisor"

validation {
condition = length(trimspace(var.action_group_short_name)) >= 1 && length(var.action_group_short_name) <= 12
error_message = "action_group_short_name must be 1-12 characters."
}
}

variable "activity_log_alert_name" {
description = "Base name of the Activity Log Alert. If append_random_suffix is true, the final name will be '<base>-<suffix>'."
type = string
default = "AdvisorAlerts"
}

variable "email_address" {
description = "Email address to receive Advisor recommendation alerts."
type = string

validation {
condition = length(trimspace(var.email_address)) > 3 && can(regex("@", var.email_address))
error_message = "email_address must look like an email address."
}
}

variable "recommendation_category" {
description = "Advisor recommendation category filter (for example: Cost, Performance, HighAvailability)."
type = string
default = "Cost"
}

variable "recommendation_impact" {
description = "Advisor recommendation impact filter (for example: High, Medium, Low)."
type = string
default = "Medium"
}

variable "scope_resource_group_name" {
description = "Optional resource group name to scope the Activity Log Alert to. If null, alert is scoped to the subscription."
type = string
default = null
}

variable "enabled" {
description = "Whether the Activity Log Alert is enabled."
type = bool
default = true
}

variable "description" {
description = "Optional description for the alert."
type = string
default = ""
}

variable "tags" {
description = "A map of tags to assign to the resources."
type = map(string)
default = {}
}
34 changes: 34 additions & 0 deletions 6_monitoring-management/automation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Terraform Template - Azure Automation Account

Costa Rica

[![GitHub](https://img.shields.io/badge/--181717?logo=github&logoColor=ffffff)](https://github.com/)
[brown9804](https://github.com/brown9804)

Last updated: 2026-02-16

------------------------------------------

> This template contains Terraform configurations to create an Azure Automation Account.

<img width="650" alt="image" src="https://github.com/user-attachments/assets/9076fb43-9d42-48ef-821b-6b9ccc624e64" />

<img width="650" alt="image" src="https://github.com/user-attachments/assets/e6bac1ce-4710-45a5-b5ac-b2a083250594" />

## File Descriptions

- **main.tf**: Creates the Resource Group (AzAPI) and Automation Account.
- **variables.tf**: Input variables.
- **provider.tf**: AzureRM + AzAPI providers.
- **terraform.tfvars**: Example values.
- **outputs.tf**: Outputs (IDs/names).

## Usage

```sh
az login
terraform init -upgrade
terraform validate
terraform plan
terraform apply -auto-approve
```
Loading