Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(subscription): add defender for cloud security contact configuration #339

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
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
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The module is designed to be instantiated many times, once for each desired land
This is currently split logically into the following capabilities:

- Subscription creation and management group placement
- Microsoft Defender for Cloud (DFC) security contact
- Networking - deploy multiple vnets with:
- Hub & spoke connectivity (peering to a hub network)
- vWAN connectivity
Expand Down Expand Up @@ -65,6 +66,12 @@ module "lz_vending" {
subscription_management_group_association_enabled = true
subscription_management_group_id = "Corp"

# defender for cloud variables
subscription_dfc_contact_enabled = true
subscription_dfc_contact = {
emails = "[email protected];[email protected]"
}

# virtual network variables
virtual_network_enabled = true
virtual_networks = {
Expand Down Expand Up @@ -480,6 +487,43 @@ Type: `string`

Default: `""`

### <a name="input_subscription_dfc_contact"></a> [subscription\_dfc\_contact](#input\_subscription\_dfc\_contact)

Description: Microsoft Defender for Cloud (DFC) contact and notification configurations

### Security Contact Information - Determines who'll get email notifications from Defender for Cloud

- `notifications_by_role`: All users with these specific RBAC roles on the subscription will get email notifications. [optional - allowed values are: `AccountAdmin`, `ServiceAdmin`, `Owner` and `Contributor` - default empty]
- `emails`: List of additional email addresses which will get notifications. Multiple emails can be provided in a ; separated list. Example: "[email protected];[email protected]". [optional - default empty]
- `phone`: The security contact's phone number. [optional - default empty]
> **Note**: At least one role or email address must be provided to enable alert notification.

### Alert Notifications

- `alert_notifications`: Enables email notifications and defines the minimal alert severity. [optional - allowed values are: `Off`, `High`, `Medium` or `Low` - default `Off`]

Type:

```hcl
object({
notifications_by_role = optional(list(string), [])
emails = optional(string, "")
phone = optional(string, "")
alert_notifications = optional(string, "Off")
})
```

Default: `{}`

### <a name="input_subscription_dfc_contact_enabled"></a> [subscription\_dfc\_contact\_enabled](#input\_subscription\_dfc\_contact\_enabled)

Description: Whether to enable Microsoft Defender for Cloud (DFC) contact settings on the subscription. [optional - default `false`]
If enabled, provide settings in var.subscription\_dfc\_contact

Type: `bool`

Default: `false`

### <a name="input_subscription_display_name"></a> [subscription\_display\_name](#input\_subscription\_display\_name)

Description: The display name of the subscription alias.
Expand Down
7 changes: 7 additions & 0 deletions header.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ The module is designed to be instantiated many times, once for each desired land
This is currently split logically into the following capabilities:

- Subscription creation and management group placement
- Microsoft Defender for Cloud (DFC) security contact
- Networking - deploy multiple vnets with:
- Hub & spoke connectivity (peering to a hub network)
- vWAN connectivity
Expand Down Expand Up @@ -64,6 +65,12 @@ module "lz_vending" {
subscription_management_group_association_enabled = true
subscription_management_group_id = "Corp"

# defender for cloud variables
subscription_dfc_contact_enabled = true
subscription_dfc_contact = {
emails = "[email protected];[email protected]"
}

# virtual network variables
virtual_network_enabled = true
virtual_networks = {
Expand Down
7 changes: 7 additions & 0 deletions main.subscription.tf
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,11 @@ module "subscription" {
subscription_update_existing = var.subscription_update_existing
subscription_workload = var.subscription_workload
wait_for_subscription_before_subscription_operations = var.wait_for_subscription_before_subscription_operations
subscription_dfc_contact_enabled = var.subscription_dfc_contact_enabled
subscription_dfc_contact = {
emails = var.subscription_dfc_contact.emails
phone = var.subscription_dfc_contact.phone
alert_notifications = var.subscription_dfc_contact.alert_notifications
notifications_by_role = var.subscription_dfc_contact.notifications_by_role
}
}
51 changes: 50 additions & 1 deletion modules/subscription/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

## Overview

Creates a subscription alias, and optionally manages management group association for the resulting subscription.
Creates a subscription alias
Optionally:

- Associates the resulting subscription to a management group
- Creates the Microsoft Defender for Cloud (DFC) security contact and enables notifications

## Notes

Expand All @@ -21,6 +25,13 @@ module "subscription" {
subscription_alias_name = "my-subscription-alias"
subscription_alias_workload = "Production"
subscription_alias_management_group_id = "mymg"
subscription_dfc_contact_enabled = true
subscription_dfc_contact = {
notifications_by_role = ["Owner", "Contributor"]
emails = "[email protected];[email protected]"
phone = "+1-555-555-5555"
alert_notifications = "Medium"
}
}
```

Expand Down Expand Up @@ -111,6 +122,43 @@ Type: `string`

Default: `""`

### <a name="input_subscription_dfc_contact"></a> [subscription\_dfc\_contact](#input\_subscription\_dfc\_contact)

Description: Microsoft Defender for Cloud (DFC) contact and notification configurations

### Security Contact Information - Determines who'll get email notifications from Defender for Cloud

- `notifications_by_role`: All users with these specific RBAC roles on the subscription will get email notifications. [optional - allowed values are: `AccountAdmin`, `ServiceAdmin`, `Owner` and `Contributor` - default empty]
- `emails`: List of additional email addresses which will get notifications. Multiple emails can be provided in a ; separated list. Example: "[email protected];[email protected]". [optional - default empty]
- `phone`: The security contact's phone number. [optional - default empty]
> **Note**: At least one role or email address must be provided to enable alert notification.

### Alert Notifications

- `alert_notifications`: Enables email notifications and defines the minimal alert severity. [optional - allowed values are: `Off`, `High`, `Medium` or `Low` - default `Off`]

Type:

```hcl
object({
notifications_by_role = optional(list(string), [])
emails = optional(string, "")
phone = optional(string, "")
alert_notifications = optional(string, "Off")
})
```

Default: `{}`

### <a name="input_subscription_dfc_contact_enabled"></a> [subscription\_dfc\_contact\_enabled](#input\_subscription\_dfc\_contact\_enabled)

Description: Whether to enable Microsoft Defender for Cloud (DFC) contact settings on the subscription. [optional - default `false`]
If enabled, provide settings in var.subscription\_dfc\_contact

Type: `bool`

Default: `false`

### <a name="input_subscription_display_name"></a> [subscription\_display\_name](#input\_subscription\_display\_name)

Description: The display name of the subscription alias.
Expand Down Expand Up @@ -224,6 +272,7 @@ Default: `{}`
The following resources are used by this module:

- [azapi_resource.subscription](https://registry.terraform.io/providers/Azure/azapi/latest/docs/resources/resource) (resource)
- [azapi_resource.subscription_dfc_contact](https://registry.terraform.io/providers/Azure/azapi/latest/docs/resources/resource) (resource)
- [azapi_resource_action.subscription_association](https://registry.terraform.io/providers/Azure/azapi/latest/docs/resources/resource_action) (resource)
- [azapi_resource_action.subscription_cancel](https://registry.terraform.io/providers/Azure/azapi/latest/docs/resources/resource_action) (resource)
- [azapi_resource_action.subscription_rename](https://registry.terraform.io/providers/Azure/azapi/latest/docs/resources/resource_action) (resource)
Expand Down
13 changes: 12 additions & 1 deletion modules/subscription/header.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

## Overview

Creates a subscription alias, and optionally manages management group association for the resulting subscription.
Creates a subscription alias
Optionally:

- Associates the resulting subscription to a management group
- Creates the Microsoft Defender for Cloud (DFC) security contact and enables notifications

## Notes

Expand All @@ -20,5 +24,12 @@ module "subscription" {
subscription_alias_name = "my-subscription-alias"
subscription_alias_workload = "Production"
subscription_alias_management_group_id = "mymg"
subscription_dfc_contact_enabled = true
subscription_dfc_contact = {
notifications_by_role = ["Owner", "Contributor"]
emails = "[email protected];[email protected]"
phone = "+1-555-555-5555"
alert_notifications = "Medium"
}
}
```
32 changes: 32 additions & 0 deletions modules/subscription/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,35 @@ resource "azapi_resource_action" "subscription_cancel" {
time_sleep.wait_for_subscription_before_subscription_operations
]
}

resource "azapi_resource" "subscription_dfc_contact" {
count = var.subscription_dfc_contact_enabled ? 1 : 0
parent_id = "/subscriptions/${local.subscription_id}"
type = "Microsoft.Security/securityContacts@2020-01-01-preview"
name = "default" // The only valid name for security contact is 'default'

body = jsonencode({
properties = {
emails = var.subscription_dfc_contact.emails
phone = var.subscription_dfc_contact.phone

alertNotifications = {
state = var.subscription_dfc_contact.alert_notifications == "Off" ? var.subscription_dfc_contact.alert_notifications : "On"
minimalSeverity = var.subscription_dfc_contact.alert_notifications == "Off" ? "" : var.subscription_dfc_contact.alert_notifications
}

notificationsByRole = {
state = length(var.subscription_dfc_contact.notifications_by_role) > 0 ? "On" : "Off"
roles = var.subscription_dfc_contact.notifications_by_role
}
}
})
schema_validation_enabled = false
lifecycle {
ignore_changes = [location]
}

depends_on = [
time_sleep.wait_for_subscription_before_subscription_operations
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
variable "subscription_billing_scope" {
type = string
}

variable "subscription_alias_name" {
type = string
}

variable "subscription_display_name" {
type = string
}

variable "subscription_workload" {
type = string
}

variable "subscription_alias_enabled" {
type = bool
}

variable "subscription_use_azapi" {
type = bool
}

variable "subscription_dfc_contact_enabled" {
type = bool
}

variable "subscription_dfc_contact" {
type = object({
emails = optional(string, "")
phone = optional(string, "")
alert_notifications = optional(string, "Off")
notifications_by_role = optional(list(string), [])
})
}

module "subscription_test" {
source = "../../"
subscription_alias_name = var.subscription_alias_name
subscription_display_name = var.subscription_display_name
subscription_workload = var.subscription_workload
subscription_billing_scope = var.subscription_billing_scope
subscription_alias_enabled = var.subscription_alias_enabled
subscription_use_azapi = var.subscription_use_azapi
subscription_dfc_contact_enabled = var.subscription_dfc_contact_enabled
subscription_dfc_contact = var.subscription_dfc_contact
}

output "subscription_id" {
value = module.subscription_test.subscription_id
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
terraform {
required_version = ">= 1.3.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 3.7.0"
}
azapi = {
source = "Azure/azapi"
version = ">= 1.0.0"
}
}
}
65 changes: 65 additions & 0 deletions modules/subscription/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,68 @@ variable "wait_for_subscription_before_subscription_operations" {
The duration to wait after vending a subscription before performing subscription operations.
DESCRIPTION
}

variable "subscription_dfc_contact_enabled" {
type = bool
default = false
description = <<DESCRIPTION
Whether to enable Microsoft Defender for Cloud (DFC) contact settings on the subscription. [optional - default `false`]
If enabled, provide settings in var.subscription_dfc_contact
DESCRIPTION
}

variable "subscription_dfc_contact" {
type = object({
notifications_by_role = optional(list(string), [])
emails = optional(string, "")
phone = optional(string, "")
alert_notifications = optional(string, "Off")
})
default = {}
description = <<DESCRIPTION
Microsoft Defender for Cloud (DFC) contact and notification configurations

### Security Contact Information - Determines who'll get email notifications from Defender for Cloud

- `notifications_by_role`: All users with these specific RBAC roles on the subscription will get email notifications. [optional - allowed values are: `AccountAdmin`, `ServiceAdmin`, `Owner` and `Contributor` - default empty]
- `emails`: List of additional email addresses which will get notifications. Multiple emails can be provided in a ; separated list. Example: "[email protected];[email protected]". [optional - default empty]
- `phone`: The security contact's phone number. [optional - default empty]
> **Note**: At least one role or email address must be provided to enable alert notification.

### Alert Notifications

- `alert_notifications`: Enables email notifications and defines the minimal alert severity. [optional - allowed values are: `Off`, `High`, `Medium` or `Low` - default `Off`]

DESCRIPTION

# validate email addresses
validation {
condition = (var.subscription_dfc_contact.emails == "" || can(regex("^([\\w+-.%]+@[\\w.-]+\\.[A-Za-z]{2,4})(;[\\w+-.%]+@[\\w.-]+\\.[A-Za-z]{2,4})*$", var.subscription_dfc_contact.emails)))
error_message = "Invalid email address(es) provided. Multiple emails must be separated with a `;`"
}

# validate phone number
validation {
condition = (var.subscription_dfc_contact.phone == "" || can(regex("^[\\+0-9-]+$", var.subscription_dfc_contact.phone)))
error_message = "Invalid phone number provided. Valid characters are 0-9, '-', and '+'. An example for a valid phone number is: +1-555-555-5555"
}

# validate alert notifications
validation {
condition = contains(["Off", "High", "Medium", "Low"], var.subscription_dfc_contact.alert_notifications)
error_message = "Invalid alert_notifications_state. Valid options are Off, High, Medium, Low."
}

# validate notifications by role
validation {
condition = alltrue([for role in var.subscription_dfc_contact.notifications_by_role : contains(["Owner", "AccountAdmin", "Contributor", "ServiceAdmin"], role)])
error_message = "Invalid notifications_by_role. The supported RBAC roles are: AccountAdmin, ServiceAdmin, Owner, Contributor."
}

# validate that when alert notifications are enabled, an email or role is also provided
validation {
condition = (var.subscription_dfc_contact.alert_notifications == "Off" ? true : var.subscription_dfc_contact.emails != "" || length(var.subscription_dfc_contact.notifications_by_role) > 0)
error_message = "To enable alert notifications, either an email address or role must be provided."
}

}
Loading
Loading