Skip to content
Draft
Show file tree
Hide file tree
Changes from 8 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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Terraform module which creates an Azure Key Vault.
- Role-based access control (RBAC) authorization enabled by default.
- Public network access denied by default.
- Audit logs sent to given Log Analytics workspace by default.
- Metric alerts sent to given action group by default:
- Reduced availability

## Development

Expand Down
7 changes: 7 additions & 0 deletions examples/basic/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ module "log_analytics" {
location = var.location
}

resource "azurerm_monitor_action_group" "this" {
name = "ag-${random_id.this.hex}"
resource_group_name = var.resource_group_name
short_name = "Action"
}

module "key_vault" {
# source = "github.com/equinor/terraform-azurerm-key-vault"
source = "../.."
Expand All @@ -26,6 +32,7 @@ module "key_vault" {
resource_group_name = var.resource_group_name
location = var.location
log_analytics_workspace_id = module.log_analytics.workspace_id
action_group_id = azurerm_monitor_action_group.this.id
}

# Give current client full access to Key Vault secrets
Expand Down
80 changes: 20 additions & 60 deletions main.tf
Original file line number Diff line number Diff line change
@@ -1,27 +1,10 @@
locals {
access_policies = [
for p in var.access_policies : {
tenant_id = data.azurerm_client_config.current.tenant_id
application_id = ""
object_id = p.object_id
secret_permissions = p.secret_permissions
certificate_permissions = p.certificate_permissions
key_permissions = p.key_permissions
storage_permissions = []
}
]
module "vault" {
source = "./modules/vault"

diagnostic_setting_metric_categories = ["AllMetrics"]
}

data "azurerm_client_config" "current" {}

resource "azurerm_key_vault" "this" {
name = var.vault_name
location = var.location
resource_group_name = var.resource_group_name
sku_name = "standard"
tenant_id = data.azurerm_client_config.current.tenant_id
vault_name = var.vault_name
resource_group_name = var.resource_group_name
location = var.location
log_analytics_workspace_id = var.log_analytics_workspace_id

soft_delete_retention_days = var.soft_delete_retention_days
purge_protection_enabled = var.purge_protection_enabled
Expand All @@ -30,50 +13,27 @@ resource "azurerm_key_vault" "this" {
enabled_for_disk_encryption = var.enabled_for_disk_encryption
enabled_for_template_deployment = var.enabled_for_template_deployment

access_policy = local.access_policies
access_policies = var.access_policies
enable_rbac_authorization = var.enable_rbac_authorization

public_network_access_enabled = var.public_network_access_enabled
public_network_access_enabled = var.public_network_access_enabled
network_acls_default_action = var.network_acls_default_action
network_acls_bypass_azure_services = var.network_acls_bypass_azure_services
network_acls_ip_rules = var.network_acls_ip_rules
network_acls_virtual_network_subnet_ids = var.network_acls_virtual_network_subnet_ids

network_acls {
default_action = var.network_acls_default_action
bypass = var.network_acls_bypass_azure_services ? "AzureServices" : "None"
ip_rules = var.network_acls_ip_rules
virtual_network_subnet_ids = var.network_acls_virtual_network_subnet_ids
}
diagnostic_setting_name = var.diagnostic_setting_name
diagnostic_setting_enabled_log_categories = var.diagnostic_setting_enabled_log_categories
diagnostic_setting_enabled_metric_categories = var.diagnostic_setting_enabled_metric_categories

tags = var.tags

lifecycle {
# Prevent accidental destroy of Key Vault.
prevent_destroy = true
}
}

resource "azurerm_monitor_diagnostic_setting" "this" {
name = var.diagnostic_setting_name
target_resource_id = azurerm_key_vault.this.id
log_analytics_workspace_id = var.log_analytics_workspace_id

# "log_analytics_destination_type" is unconfigurable for Key Vault.
# Ref: https://registry.terraform.io/providers/hashicorp/azurerm/3.65.0/docs/resources/monitor_diagnostic_setting#log_analytics_destination_type
log_analytics_destination_type = null

dynamic "enabled_log" {
for_each = toset(var.diagnostic_setting_enabled_log_categories)
module "alerts" {
source = "./modules/alerts"

content {
category = enabled_log.value
}
}
vault_id = module.vault.vault_id
action_group_id = var.action_group_id

dynamic "metric" {
for_each = toset(concat(local.diagnostic_setting_metric_categories, var.diagnostic_setting_enabled_metric_categories))

content {
# Azure expects explicit configuration of both enabled and disabled metric categories.
category = metric.value
enabled = contains(var.diagnostic_setting_enabled_metric_categories, metric.value)
}
}
tags = var.tags
}
3 changes: 3 additions & 0 deletions modules/alerts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Alerts submodule

<!-- TODO(@hknutsen): Write a description here. -->
46 changes: 46 additions & 0 deletions modules/alerts/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
locals {
parsed_vault_id = provider::azurerm::parse_resource_id(var.vault_id)
vault_name = local.parsed_vault_id["resource_name"]
resource_group_name = local.parsed_vault_id["resource_group_name"]

metric_alerts = {
"availability" = {
name = "Reduced availability"
description = ""
metric_name = "Availability"
aggregation = "Average"
operator = "LessThan"
threshold = 100
frequency = "PT1M"
window_size = "PT5M"
severity = 1 # Error
}
}
}

resource "azurerm_monitor_metric_alert" "this" {
for_each = local.metric_alerts

name = "${each.value.name} - ${local.vault_name}"
resource_group_name = local.resource_group_name
scopes = [var.vault_id]
description = each.value.description

criteria {
metric_namespace = "Microsoft.KeyVault/vaults"
metric_name = each.value.metric_name
aggregation = each.value.aggregation
operator = each.value.operator
threshold = each.value.threshold
}

frequency = each.value.frequency
window_size = each.value.window_size
severity = each.value.severity

action {
action_group_id = var.action_group_id
}

tags = var.tags
}
Empty file added modules/alerts/outputs.tf
Empty file.
16 changes: 16 additions & 0 deletions modules/alerts/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# TODO(@hknutsen): Should this be a list of vault IDs?
variable "vault_id" {
description = "The ID of the Key Vault to create these alerts for."
type = string
}

variable "action_group_id" {
description = "The ID of the action group to send alerts to."
type = string
}

variable "tags" {
description = "A map of tags to assign to the resources."
type = map(string)
default = {}
}
10 changes: 10 additions & 0 deletions modules/alerts/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
terraform {
required_version = ">= 1.8.0"

required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 3.0.0" # TODO(@hknutsen): Investigate if this submodule requires a higher minimum version.
}
}
}
3 changes: 3 additions & 0 deletions modules/vault/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Vault submodule

<!-- TODO(@hknutsen): Write a description here. -->
79 changes: 79 additions & 0 deletions modules/vault/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
locals {
access_policies = [
for p in var.access_policies : {
tenant_id = data.azurerm_client_config.current.tenant_id
application_id = ""
object_id = p.object_id
secret_permissions = p.secret_permissions
certificate_permissions = p.certificate_permissions
key_permissions = p.key_permissions
storage_permissions = []
}
]

diagnostic_setting_metric_categories = ["AllMetrics"]
}

data "azurerm_client_config" "current" {}

resource "azurerm_key_vault" "this" {
name = var.vault_name
location = var.location
resource_group_name = var.resource_group_name
sku_name = "standard"
tenant_id = data.azurerm_client_config.current.tenant_id

soft_delete_retention_days = var.soft_delete_retention_days
purge_protection_enabled = var.purge_protection_enabled

enabled_for_deployment = var.enabled_for_deployment
enabled_for_disk_encryption = var.enabled_for_disk_encryption
enabled_for_template_deployment = var.enabled_for_template_deployment

access_policy = local.access_policies
enable_rbac_authorization = var.enable_rbac_authorization

public_network_access_enabled = var.public_network_access_enabled

network_acls {
default_action = var.network_acls_default_action
bypass = var.network_acls_bypass_azure_services ? "AzureServices" : "None"
ip_rules = var.network_acls_ip_rules
virtual_network_subnet_ids = var.network_acls_virtual_network_subnet_ids
}

tags = var.tags

lifecycle {
# Prevent accidental destroy of Key Vault.
prevent_destroy = true
}
}

resource "azurerm_monitor_diagnostic_setting" "this" {
name = var.diagnostic_setting_name
target_resource_id = azurerm_key_vault.this.id
log_analytics_workspace_id = var.log_analytics_workspace_id

# "log_analytics_destination_type" is unconfigurable for Key Vault.
# Ref: https://registry.terraform.io/providers/hashicorp/azurerm/3.65.0/docs/resources/monitor_diagnostic_setting#log_analytics_destination_type
log_analytics_destination_type = null

dynamic "enabled_log" {
for_each = toset(var.diagnostic_setting_enabled_log_categories)

content {
category = enabled_log.value
}
}

dynamic "metric" {
for_each = toset(concat(local.diagnostic_setting_metric_categories, var.diagnostic_setting_enabled_metric_categories))

content {
# Azure expects explicit configuration of both enabled and disabled metric categories.
category = metric.value
enabled = contains(var.diagnostic_setting_enabled_metric_categories, metric.value)
}
}
}
14 changes: 14 additions & 0 deletions modules/vault/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
output "vault_id" {
description = "The ID of this Key Vault."
value = azurerm_key_vault.this.id
}

output "vault_name" {
description = "The name of this Key Vault."
value = azurerm_key_vault.this.name
}

output "vault_uri" {
description = "The URI of this Key Vault."
value = azurerm_key_vault.this.vault_uri
}
Loading