diff --git a/modules/sentinel-playbook/README.md b/modules/sentinel-playbook/README.md new file mode 100644 index 0000000..497d67c --- /dev/null +++ b/modules/sentinel-playbook/README.md @@ -0,0 +1,49 @@ + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.2 | +| [azuread](#requirement\_azuread) | ~> 2.22 | +| [azurerm](#requirement\_azurerm) | ~> 3.0 | +| [null](#requirement\_null) | ~> 3.2.1 | + +## Providers + +| Name | Version | +|------|---------| +| [azuread](#provider\_azuread) | 2.42.0 | +| [null](#provider\_null) | 3.2.1 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [azure\_role\_assignment](#module\_azure\_role\_assignment) | git::git@github.com:quantum-sec/package-azure.git//modules/azure-role-assignment | 1.6.1 | +| [azure\_sentinel\_playbooks](#module\_azure\_sentinel\_playbooks) | git::git@github.com:quantum-sec/package-azure.git//modules/azure-arm-deployment | 1.6.1 | + +## Resources + +| Name | Type | +|------|------| +| [null_resource.template_hash](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource | +| [azuread_service_principal.builtin_app](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/data-sources/service_principal) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [arm\_deployment\_name\_prefix](#input\_arm\_deployment\_name\_prefix) | A unique string prepended to the ARM deployment name to ensure it is globally unique (i.e. your company name). | `string` | n/a | yes | +| [parameters\_override](#input\_parameters\_override) | Key/Value map to be applied to the arm script parameters. | `map(string)` | `{}` | no | +| [playbook\_template](#input\_playbook\_template) | The JSON template of the playbook to be deployed | `string` | n/a | yes | +| [resource\_group\_name](#input\_resource\_group\_name) | The name of the resource group in which this resource will be provisioned. | `string` | n/a | yes | +| [role\_definition\_name](#input\_role\_definition\_name) | The name of role definitiion in Azure subscription that is required to be assigned. | `string` | `"Microsoft Sentinel Automation Contributor"` | no | +| [sentinel\_principal\_id](#input\_sentinel\_principal\_id) | This is the Microsoft Sentinel Application ID that we can extract from Azure AD enterprise application. | `string` | `null` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [logic\_app\_id](#output\_logic\_app\_id) | The ID of the LogicApp. | +| [output\_content](#output\_output\_content) | The JSON content of the outputs of the ARM template deployment. | + diff --git a/modules/sentinel-playbook/main.tf b/modules/sentinel-playbook/main.tf new file mode 100644 index 0000000..a9609c9 --- /dev/null +++ b/modules/sentinel-playbook/main.tf @@ -0,0 +1,78 @@ +# --------------------------------------------------------------------------------------------------------------------- +# DEPLOY A MICROSOFT SENTINEL PLAYBOOK +# --------------------------------------------------------------------------------------------------------------------- + +terraform { + required_version = ">= 1.2" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0" + } + azuread = { + source = "hashicorp/azuread" + version = "~> 2.22" + } + null = { + source = "hashicorp/null" + version = "~> 3.2.1" + } + } +} + +resource "null_resource" "template_hash" { + # null_resource.parameters.id used to force recreation of module.azure_sentinel_playbooks via local.arm_deployment_name + # this null_resource will get a new id when any of the triggers change + triggers = { + template_md5 = md5(var.playbook_template) + parameters_md5 = md5(jsonencode(var.parameters_override)) + } +} + +module "azure_sentinel_playbooks" { + source = "git::git@github.com:quantum-sec/package-azure.git//modules/azure-arm-deployment?ref=1.6.1" + + depends_on = [ + null_resource.template_hash, + ] + + # logic_app_name is not controlled via this name - this is the deployment + name = substr("${var.arm_deployment_name_prefix}-playbook-${null_resource.template_hash.id}", 0, 64) + resource_group_name = var.resource_group_name + deployment_mode = "Incremental" + + # Note that updating this file after the initial deployment will fail to `apply` because the corresponding + # parameters are not sent. You will need to first `destroy` then `apply` with the changes. + # See https://github.com/terraform-providers/terraform-provider-azurerm/issues/8840 + arm_script = var.playbook_template + parameters_override = var.parameters_override +} + +# --------------------------------------------------------------------------------------------------------------------- +# DATA SOURCE FOR AZURE ROLE ASSIGNMENT +# --------------------------------------------------------------------------------------------------------------------- + +locals { + playbooks_template_output = jsondecode(module.azure_sentinel_playbooks.output_content) +} + +data "azuread_service_principal" "builtin_app" { + count = var.sentinel_principal_id == null ? 1 : 0 + display_name = "Azure Security Insights" +} + +# --------------------------------------------------------------------------------------------------------------------- +# CREATE AZURE ROLE ASSIGNMENT FOR AZURE SECURITY INSIGHT APP +# --------------------------------------------------------------------------------------------------------------------- + +module "azure_role_assignment" { + source = "git::git@github.com:quantum-sec/package-azure.git//modules/azure-role-assignment?ref=1.6.1" + + depends_on = [ + module.azure_sentinel_playbooks, + ] + + scope = local.playbooks_template_output["logicAppId"]["value"] + role_definition_name = var.role_definition_name + principal_id = coalesce(var.sentinel_principal_id, (can(data.azuread_service_principal.builtin_app[0].id) ? data.azuread_service_principal.builtin_app[0].id : null)) +} diff --git a/modules/sentinel-playbook/outputs.tf b/modules/sentinel-playbook/outputs.tf new file mode 100644 index 0000000..1d4a0e9 --- /dev/null +++ b/modules/sentinel-playbook/outputs.tf @@ -0,0 +1,9 @@ +output "logic_app_id" { + description = "The ID of the LogicApp." + value = local.playbooks_template_output["logicAppId"].value +} + +output "output_content" { + description = "The JSON content of the outputs of the ARM template deployment." + value = module.azure_sentinel_playbooks.output_content +} diff --git a/modules/sentinel-playbook/vars.tf b/modules/sentinel-playbook/vars.tf new file mode 100644 index 0000000..5809a73 --- /dev/null +++ b/modules/sentinel-playbook/vars.tf @@ -0,0 +1,32 @@ +variable "resource_group_name" { + description = "The name of the resource group in which this resource will be provisioned." + type = string +} + +variable "arm_deployment_name_prefix" { + description = "A unique string prepended to the ARM deployment name to ensure it is globally unique (i.e. your company name)." + type = string +} + +variable "playbook_template" { + description = "The JSON template of the playbook to be deployed" + type = string +} + +variable "parameters_override" { + description = "Key/Value map to be applied to the arm script parameters." + type = map(string) + default = {} +} + +variable "role_definition_name" { + description = "The name of role definitiion in Azure subscription that is required to be assigned." + type = string + default = "Microsoft Sentinel Automation Contributor" +} + +variable "sentinel_principal_id" { + description = "This is the Microsoft Sentinel Application ID that we can extract from Azure AD enterprise application." + type = string + default = null +}