diff --git a/aws/README.md b/aws/README.md index 30db483..9177635 100644 --- a/aws/README.md +++ b/aws/README.md @@ -24,11 +24,11 @@ Before you begin the following must be configured on the workstation running Ter Typically, the [AWS CLI](https://aws.amazon.com/cli/) will have been previously installed and `aws configure` run and with `$AWS_PROFILE` set to the appropriate credential profile in `~/.aws/credentials` -Also recommend that the [Lacework CLI](https://github.com/lacework/go-sdk) be installed and the `[default]` profile is associated with the applicable Lacework Account `api_key` and `api_secret` in `~/.lacework.toml` +Also recommend that the [Lacework CLI](https://github.com/lacework/go-sdk/wiki/CLI-Documentation) be installed and the `[default]` profile is associated with the applicable Lacework Account `api_key` and `api_secret` in `~/.lacework.toml` ## Usage -**IMPORTANT:** We use the `master` branch in source just as an example. In your code, *do NOT pin to master* because there may +**IMPORTANT:** We use the `master` branch in source just as an example. In your code, **do NOT pin to master** because there may be breaking changes between releases. Instead we recommend to pin to the release tag (e.g. `?ref=tags/v0.1.0`) of one of our [latest releases](https://github.com/lacework/terraform-provisioning/releases). diff --git a/azure/README.md b/azure/README.md index 6c67134..c9a2104 100644 --- a/azure/README.md +++ b/azure/README.md @@ -11,6 +11,8 @@ Trail analysis. - *Owner Role* at the Subscription level - [Lacework API Key](https://support.lacework.com/hc/en-us/articles/360011403853-Generate-API-Access-Keys-and-Tokens) +Also recommend that the [Lacework CLI](https://github.com/lacework/go-sdk/wiki/CLI-Documentation) be installed and the `[default]` profile is associated with the applicable Lacework Account `api_key` and `api_secret` in `~/.lacework.toml` + ## Login via the Azure CLI In order to integrate Lacework with Azure you will need to login to your Azure console via the Azure CLI by running the command: @@ -18,26 +20,58 @@ the Azure CLI by running the command: $ az login ``` -### Run Terraform -1. Clone this repository: https://github.com/lacework/terraform-provisioning -2. Change directories into `terraform-provisioning/azure` -3. Create a new file called `terraform.tfvars` with the following content: +## Usage -``` -prefix = "" -identifier_uris = [ - "https://.lacework.net" -] -lacework_account = "" -lacework_api_key = "" -lacework_api_secret = "" -``` -or use environment variables to avoid hardcoding API keys and secrets. +**IMPORTANT:** We use the `master` branch in source just as an example. In your code, **do NOT pin to master** because there may +be breaking changes between releases. Instead we recommend to pin to the release tag (e.g. `?ref=tags/v0.1.0`) of one of +our [latest releases](https://github.com/lacework/terraform-provisioning/releases). + +### Enable New Azure Compliance and Activity Log Integrations +```hcl +provider "azuread" {} + +provider "azurerm" { + features {} +} + +provider "lacework" {} + +module "az_config" { + source = "git::https://github.com/lacework/terraform-provisioning.git//azure/modules/config?ref=master" +} + +module "az_activity_log" { + source = "git::https://github.com/lacework/terraform-provisioning.git//azure/modules/activity_log?ref=master" + + use_existing_ad_application = true + application_id = module.az_config.application_id + application_password = module.az_config.application_password + service_principal_id = module.az_config.service_principal_id +} ``` -export TF_VAR_lacework_api_key= -export TF_VAR_lacework_api_secret= -``` - -5. Run `terraform init` -6. Run `terraform apply` + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| application_name | The name of the Azure Active Directory Applicaiton | `string` | lacework_security_audit | no | +| application_identifier_uris | A list of user-defined URI(s) for the Lacework AD Application | `list(string)` | ["https://securityaudit.lacework.net"] | no | +| key_vault_ids | A list of Key Vault Ids used in your subscription for the Lacework AD App to have access to | `list(string)` | [] | no | +| tenant_id | A Tenant ID different from the default defined inside the provider | `string` | "" | no | +| password_length | The length of the Lacework AD Application password | `number` | 30 | no | +| use_existing_ad_application | Set this to true to use an existing Active Directory Application | `bool` | false | no | +| application_id | The Active Directory Application id to use (required when use_existing_ad_application is set to true) | `string` | "" | no | +| application_password | The Active Directory Application password to use (required when use_existing_ad_application is set to true) | `string` | "" | no | +| service_principal_id | The Service Principal id to use (required when use_existing_ad_application is set to true) | `string` | "" | no | +| prefix | The prefix that will be use at the beginning of every generated resource | `string` | l4c3w0rk | no | +| lacework_integration_name | The name of the integration in Lacework. This input is available in both the config, and the activity_log module | `string` | TF config | no | +| wait_time | Define a custom delay between cloud resource provision and Lacework external integration to avoid errors while things settle down. Use `10s` for 10 seconds, `5m` for 5 minutes. | `string` | `10s` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| application_id | The Lacework AD Application id | +| application_password | The Lacework AD Application password | +| service_principal_id | The Lacework Service Principal id | diff --git a/azure/main.tf b/azure/main.tf index fa28d4f..a1dda28 100644 --- a/azure/main.tf +++ b/azure/main.tf @@ -1,231 +1,19 @@ -provider "azuread" { - version = "=0.7.0" -} +provider "azuread" {} provider "azurerm" { - version = "=1.44.0" -} - -provider "random" { - version = "=2.2" -} - -locals { - resource_group = var.resource_group == null ? "${var.prefix}lwresourcegroup" : var.resource_group - storage = var.storage == null ? "${var.prefix}lwstorage" : var.storage - storage_queue = var.storage_queue == null ? "${var.prefix}lwstoragequeue" : var.storage_queue - event_subscription = var.event_subscription == null ? "${var.prefix}lweventsub" : var.event_subscription - log_profile = var.log_profile == null ? "${var.prefix}lwlogprofile" : var.log_profile -} - -resource "azuread_application" "default" { - name = var.app_name - identifier_uris = var.identifier_uris - - // Microsoft Graph - required_resource_access { - resource_app_id = "00000003-0000-0000-c000-000000000000" - - resource_access { - id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d" - type = "Scope" - } - - resource_access { - id = "df021288-bdef-4463-88db-98f22de89214" - type = "Role" - } - } - - // AAD Graph API - required_resource_access { - resource_app_id = "00000002-0000-0000-c000-000000000000" - - resource_access { - id = "5778995a-e1bf-45b8-affa-663a9f3f4d04" - type = "Role" - } - } - - // Azure Storage - required_resource_access { - resource_app_id = "e406a681-f3d4-42a8-90b6-c2b029497af1" - - resource_access { - id = "03e0da56-190b-40ad-a80c-ea378c433f7f" - type = "Scope" - } - } - - // Azure Key Vault - required_resource_access { - resource_app_id = "cfa8b339-82a2-471a-a3c9-0fc0be7a4093" - - resource_access { - id = "f53da476-18e3-4152-8e01-aec403e6edc0" - type = "Scope" - } - } -} - -resource "random_uuid" "generator" {} - -resource "azuread_application_password" "client_secret" { - application_object_id = azuread_application.default.id - value = random_uuid.generator.result - end_date = "2299-12-31T01:02:03Z" -} - -resource "azuread_service_principal" "default" { - application_id = azuread_application.default.application_id -} - -data "azurerm_subscriptions" "available" {} - -resource "azurerm_role_assignment" "ex" { - count = length(data.azurerm_subscriptions.available.subscriptions) - - scope = "/subscriptions/${data.azurerm_subscriptions.available.subscriptions[count.index].subscription_id}" - role_definition_name = "Reader" - principal_id = azuread_service_principal.default.id -} - -data "azurerm_subscription" "primary" {} - -resource "azurerm_key_vault_access_policy" "default" { - count = length(var.key_vault_ids) - - key_vault_id = var.key_vault_ids[count.index] - object_id = azuread_service_principal.default.id - tenant_id = data.azurerm_subscription.primary.tenant_id - - key_permissions = [ - "List" - ] - secret_permissions = [ - "List" - ] -} - -// ------------------------------------------------------------------------------ - -resource "azurerm_resource_group" "default" { - name = local.resource_group - location = var.location -} - -resource "azurerm_storage_account" "default" { - name = local.storage - account_kind = "StorageV2" - account_replication_type = "LRS" - account_tier = "Standard" - enable_blob_encryption = true - enable_https_traffic_only = true - location = var.location - resource_group_name = azurerm_resource_group.default.name -} - -resource "azurerm_storage_queue" "default" { - name = local.storage_queue - storage_account_name = azurerm_storage_account.default.name -} - -resource "azurerm_eventgrid_event_subscription" "default" { - name = local.event_subscription - scope = azurerm_storage_account.default.id - - storage_queue_endpoint { - storage_account_id = azurerm_storage_account.default.id - queue_name = azurerm_storage_queue.default.name - } - - subject_filter { - subject_begins_with = "/blobServices/default/containers/insights-operational-logs/" - } - - included_event_types = [ - "Microsoft.Storage.BlobCreated" - ] + features {} } -resource "azurerm_monitor_log_profile" "default" { - name = local.log_profile - - categories = [ - "Action", - "Delete", - "Write", - ] - - locations = var.log_profile_locations - - storage_account_id = azurerm_storage_account.default.id - - retention_policy { - enabled = true - days = 7 - } -} - -resource "azurerm_role_definition" "default" { - name = "${var.prefix}lwrole" - description = "Monitors Activity Log" - - scope = data.azurerm_subscription.primary.id - assignable_scopes = [ - data.azurerm_subscription.primary.id - ] - - permissions { - actions = [ - "Microsoft.Resources/subscriptions/resourceGroups/read", - "Microsoft.Storage/storageAccounts/read", - "Microsoft.Storage/storageAccounts/blobServices/containers/read", - "Microsoft.Storage/storageAccounts/queueServices/queues/read", - "Microsoft.EventGrid/eventSubscriptions/read", - "Microsoft.Storage/storageAccounts/listkeys/action" - ] - - data_actions = [ - "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read", - "Microsoft.Storage/storageAccounts/queueServices/queues/messages/read", - "Microsoft.Storage/storageAccounts/queueServices/queues/messages/delete" - ] - } -} - -resource "azurerm_role_assignment" "default" { - role_definition_id = azurerm_role_definition.default.id - principal_id = azuread_service_principal.default.id - scope = data.azurerm_subscription.primary.id -} - -provider "lacework" { - account = var.lacework_account - api_key = var.lacework_api_key - api_secret = var.lacework_api_secret -} +provider "lacework" {} -resource "lacework_integration_azure_cfg" "default" { - name = var.lacework_integration_config_name - tenant_id = data.azurerm_subscription.primary.tenant_id - credentials { - client_id = azuread_application.default.application_id - client_secret = azuread_application_password.client_secret.value - } - depends_on = [ azurerm_eventgrid_event_subscription.default ] +module "az_config" { + source = "./modules/config" } -resource "lacework_integration_azure_al" "default" { - name = var.lacework_integration_activitylog_name - tenant_id = data.azurerm_subscription.primary.tenant_id - queue_url = "https://${azurerm_storage_account.default.name}.queue.core.windows.net/${azurerm_storage_queue.default.name}" - credentials { - client_id = azuread_application.default.application_id - client_secret = azuread_application_password.client_secret.value - } - depends_on = [ - azurerm_eventgrid_event_subscription.default, - lacework_integration_azure_cfg.default - ] +module "az_activity_log" { + source = "./modules/activity_log" + use_existing_ad_application = true + application_id = module.az_config.application_id + application_password = module.az_config.application_password + service_principal_id = module.az_config.service_principal_id } diff --git a/azure/modules/activity_log/examples/custom-activity-log/main.tf b/azure/modules/activity_log/examples/custom-activity-log/main.tf new file mode 100644 index 0000000..704ef93 --- /dev/null +++ b/azure/modules/activity_log/examples/custom-activity-log/main.tf @@ -0,0 +1,19 @@ +provider "azuread" {} + +provider "azurerm" { + features {} +} + +provider "lacework" {} + +module "az_activity_log" { + source = "../../" + application_identifier_uris = ["https://account.lacework.net"] + application_name = "my-custom-application-name" + key_vault_ids = ["vault-id-1", "vault-id-2", "vault-id-3", "vault-id-4"] + tenant_id = "123abc12-abcd-1234-abcd-abcd12340123" + password_lenght = 16 + lacework_integration_name = "custom name" + prefix = "customprefix" + location = "Central US" +} diff --git a/azure/modules/activity_log/examples/default-activity-log/main.tf b/azure/modules/activity_log/examples/default-activity-log/main.tf new file mode 100644 index 0000000..d8216d2 --- /dev/null +++ b/azure/modules/activity_log/examples/default-activity-log/main.tf @@ -0,0 +1,11 @@ +provider "azuread" {} + +provider "azurerm" { + features {} +} + +provider "lacework" {} + +module "az_activity_log" { + source = "../../" +} diff --git a/azure/modules/activity_log/main.tf b/azure/modules/activity_log/main.tf new file mode 100644 index 0000000..7e28590 --- /dev/null +++ b/azure/modules/activity_log/main.tf @@ -0,0 +1,131 @@ +locals { + application_id = var.use_existing_ad_application ? var.application_id : module.az_al_ad_application.application_id + application_password = var.use_existing_ad_application ? var.application_password : module.az_al_ad_application.application_password + service_principal_id = var.use_existing_ad_application ? var.service_principal_id : module.az_al_ad_application.service_principal_id +} + +module "az_al_ad_application" { + source = "../ad_application" + create = var.use_existing_ad_application ? false : true + application_name = var.application_name + application_identifier_uris = var.application_identifier_uris + key_vault_ids = var.key_vault_ids + tenant_id = var.tenant_id + password_length = var.password_length +} + +resource "azurerm_resource_group" "lacework" { + name = "${var.prefix}-group" + location = var.location +} + +# NOTE: storage name can only consist of lowercase letters and numbers, +# and must be between 3 and 24 characters long +resource "azurerm_storage_account" "lacework" { + name = "${var.prefix}storage" + account_kind = "StorageV2" + account_tier = "Standard" + account_replication_type = "LRS" + enable_https_traffic_only = true + location = var.location + resource_group_name = azurerm_resource_group.lacework.name + #enable_blob_encryption = true +} + +resource "azurerm_storage_queue" "lacework" { + name = "${var.prefix}-queue" + storage_account_name = azurerm_storage_account.lacework.name +} + +resource "azurerm_eventgrid_event_subscription" "lacework" { + name = "${var.prefix}-subscription" + scope = azurerm_storage_account.lacework.id + + storage_queue_endpoint { + queue_name = azurerm_storage_queue.lacework.name + storage_account_id = azurerm_storage_account.lacework.id + } + + subject_filter { + subject_begins_with = "/blobServices/default/containers/insights-operational-logs/" + } + + included_event_types = [ + "Microsoft.Storage.BlobCreated" + ] +} + +resource "azurerm_monitor_log_profile" "lacework" { + name = "${var.prefix}-log-profile" + locations = var.log_profile_locations + storage_account_id = azurerm_storage_account.lacework.id + + categories = [ + "Action", + "Delete", + "Write", + ] + + # TODO @afiune customize these settings + retention_policy { + enabled = true + days = 7 + } +} + +# TODO @afiune maybe we could add a subscription_id variable +data "azurerm_subscription" "primary" {} +resource "azurerm_role_definition" "lacework" { + name = "${var.prefix}-role" + description = "Used by Lacework to monitor Activity Logs" + scope = data.azurerm_subscription.primary.id + + assignable_scopes = [ + data.azurerm_subscription.primary.id + ] + + permissions { + actions = [ + "Microsoft.Resources/subscriptions/resourceGroups/read", + "Microsoft.Storage/storageAccounts/read", + "Microsoft.Storage/storageAccounts/blobServices/containers/read", + "Microsoft.Storage/storageAccounts/queueServices/queues/read", + "Microsoft.EventGrid/eventSubscriptions/read", + "Microsoft.Storage/storageAccounts/listkeys/action" + ] + + data_actions = [ + "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read", + "Microsoft.Storage/storageAccounts/queueServices/queues/messages/read", + "Microsoft.Storage/storageAccounts/queueServices/queues/messages/delete" + ] + } +} + +resource "azurerm_role_assignment" "lacework" { + role_definition_id = azurerm_role_definition.lacework.id + principal_id = local.service_principal_id + scope = data.azurerm_subscription.primary.id +} + +# wait for X seconds for the Azure resources to be created +resource "time_sleep" "wait_time" { + create_duration = var.wait_time + depends_on = [ + azurerm_eventgrid_event_subscription.lacework, + azurerm_monitor_log_profile.lacework, + azurerm_role_assignment.lacework, + module.az_al_ad_application + ] +} + +resource "lacework_integration_azure_al" "default" { + name = var.lacework_integration_name + tenant_id = module.az_al_ad_application.tenant_id + queue_url = "https://${azurerm_storage_account.lacework.name}.queue.core.windows.net/${azurerm_storage_queue.lacework.name}" + credentials { + client_id = local.application_id + client_secret = local.application_password + } + depends_on = [time_sleep.wait_time] +} diff --git a/azure/modules/activity_log/output.tf b/azure/modules/activity_log/output.tf new file mode 100644 index 0000000..5638086 --- /dev/null +++ b/azure/modules/activity_log/output.tf @@ -0,0 +1,20 @@ +output "application_password" { + value = local.application_password + description = "The Lacework AD Application password" + sensitive = true +} + +output "application_id" { + value = local.application_id + description = "The Lacework AD Application id" +} + +output "service_principal_id" { + value = module.az_cfg_ad_application.service_principal_id + description = "The Lacework Service Principal id" +} + +output "tenant_id" { + value = module.az_al_ad_application.tenant_id + description = "A Tenant ID used to configure the AD Application" +} diff --git a/azure/modules/activity_log/variables.tf b/azure/modules/activity_log/variables.tf new file mode 100644 index 0000000..73f4c8d --- /dev/null +++ b/azure/modules/activity_log/variables.tf @@ -0,0 +1,132 @@ +variable "location" { + type = string + description = "The Azure Region in which all resources in this example should be created." + default = "West US 2" +} + +# NOTE: this prefix is used in all resources and we have a limitatino with the +# storage name that can only consist of lowercase letters and numbers, and must +# be between 3 and 24 characters long +variable "prefix" { + type = string + default = "l4c3w0rk" + description = "The prefix that will be use at the beginning of every generated resource" +} + +variable "application_name" { + type = string + default = "lacework_security_audit" + description = "The name of the Azure Active Directory Applicaiton" +} + +# TODO @afiune do we need this? +variable "application_identifier_uris" { + type = list(string) + description = "A list of user-defined URI(s) for the Lacework AD Application" + default = [ + "https://securityaudit.lacework.net" + ] +} + +# If some of the subscriptions use Key Vault services, we need to the +# Azure App to have access to each Key Vault used in your subscriptions. +variable "key_vault_ids" { + type = list(string) + description = "A list of Key Vault Ids used in your subscription for the Lacework AD App to have access to" + default = [] +} + +variable "tenant_id" { + type = string + default = "" + description = "A Tenant ID different from the default defined inside the provider" +} + +variable "password_length" { + type = number + default = 30 + description = "The length of the Lacework AD Application password" +} + +variable "wait_time" { + type = string + default = "10s" + description = "Amount of time to wait before the Lacework resources are provisioned" +} + +variable "lacework_integration_name" { + type = string + default = "TF activity log" +} + +variable "use_existing_ad_application" { + type = bool + default = false + description = "Set this to true to use an existing Active Directory Application" +} + +variable "application_id" { + type = string + default = "" + description = "The Active Directory Application id to use (required when use_existing_ad_application is set to true)" +} + +variable "application_password" { + type = string + default = "" + description = "The Active Directory Application password to use (required when use_existing_ad_application is set to true)" +} + +variable "service_principal_id" { + type = string + default = "" + description = "The Service Principal id to use (required when use_existing_ad_application is set to true)" +} + +variable "log_profile_locations" { + type = list(string) + description = "List of regions for which Activity Log events are stored or streamed" + default = [ + "eastasia", + "southeastasia", + "centralus", + "eastus", + "eastus2", + "westus", + "northcentralus", + "southcentralus", + "northeurope", + "westeurope", + "japanwest", + "japaneast", + "brazilsouth", + "australiaeast", + "australiasoutheast", + "southindia", + "centralindia", + "westindia", + "canadacentral", + "canadaeast", + "uksouth", + "ukwest", + "westcentralus", + "westus2", + "koreacentral", + "koreasouth", + "francecentral", + "francesouth", + "australiacentral", + "australiacentral2", + "uaecentral", + "uaenorth", + "southafricanorth", + "southafricawest", + "switzerlandnorth", + "switzerlandwest", + "germanynorth", + "germanywestcentral", + "norwaywest", + "norwayeast", + "global" + ] +} diff --git a/azure/modules/ad_application/examples/custom-ad-application/main.tf b/azure/modules/ad_application/examples/custom-ad-application/main.tf new file mode 100644 index 0000000..dc236dc --- /dev/null +++ b/azure/modules/ad_application/examples/custom-ad-application/main.tf @@ -0,0 +1,14 @@ +provider "azuread" {} + +provider "azurerm" { + features {} +} + +module "ad_application" { + source = "../../" + application_name = "lacework_custom_ad_application_name" + application_identifier_uris = ["https://account.lacework.net"] + key_vault_ids = ["vault-id-1", "vault-id-2", "vault-id-3", "vault-id-4"] + tenant_id = "123abc12-abcd-1234-abcd-abcd12340123" + password_lenght = 16 +} diff --git a/azure/modules/ad_application/examples/default-ad-application/main.tf b/azure/modules/ad_application/examples/default-ad-application/main.tf new file mode 100644 index 0000000..d50b0f5 --- /dev/null +++ b/azure/modules/ad_application/examples/default-ad-application/main.tf @@ -0,0 +1,9 @@ +provider "azuread" {} + +provider "azurerm" { + features {} +} + +module "ad_application" { + source = "../../" +} diff --git a/azure/modules/ad_application/examples/skip-creation-ad-application/main.tf b/azure/modules/ad_application/examples/skip-creation-ad-application/main.tf new file mode 100644 index 0000000..281947d --- /dev/null +++ b/azure/modules/ad_application/examples/skip-creation-ad-application/main.tf @@ -0,0 +1,10 @@ +provider "azuread" {} + +provider "azurerm" { + features {} +} + +module "ad_application" { + source = "../../" + create = false +} diff --git a/azure/modules/ad_application/main.tf b/azure/modules/ad_application/main.tf new file mode 100644 index 0000000..2400600 --- /dev/null +++ b/azure/modules/ad_application/main.tf @@ -0,0 +1,116 @@ +locals { + tenant_id = length(var.tenant_id) > 0 ? var.tenant_id : data.azurerm_subscription.primary.tenant_id + application_id = var.create ? ( + length(azuread_application.lacework) > 0 ? azuread_application.lacework[0].application_id : "" + ) : "" + application_password = var.create ? ( + length(azuread_application_password.client_secret) > 0 ? azuread_application_password.client_secret[0].value : "" + ) : "" + service_principal_id = var.create ? ( + length(azuread_service_principal.lacework) > 0 ? azuread_service_principal.lacework[0].object_id : "" + ) : "" +} + +data "azurerm_subscription" "primary" {} +resource "azuread_application" "lacework" { + count = var.create ? 1 : 0 + name = var.application_name + identifier_uris = var.application_identifier_uris + + // Microsoft Graph + required_resource_access { + resource_app_id = "00000003-0000-0000-c000-000000000000" + + resource_access { + id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d" + type = "Scope" + } + + resource_access { + id = "df021288-bdef-4463-88db-98f22de89214" + type = "Role" + } + } + + // AAD Graph API + required_resource_access { + resource_app_id = "00000002-0000-0000-c000-000000000000" + + resource_access { + id = "5778995a-e1bf-45b8-affa-663a9f3f4d04" + type = "Role" + } + } + + // Azure Storage + required_resource_access { + resource_app_id = "e406a681-f3d4-42a8-90b6-c2b029497af1" + + resource_access { + id = "03e0da56-190b-40ad-a80c-ea378c433f7f" + type = "Scope" + } + } + + // Azure Key Vault + required_resource_access { + resource_app_id = "cfa8b339-82a2-471a-a3c9-0fc0be7a4093" + + resource_access { + id = "f53da476-18e3-4152-8e01-aec403e6edc0" + type = "Scope" + } + } +} + +resource "azuread_service_principal" "lacework" { + count = var.create ? 1 : 0 + application_id = local.application_id + + # ** WORKAROUND: @afiune today it is NOT possible to automate the process of granting admin + # consent to new Active Directory Applications, though it is possible to do + # it via the AzureCLI, this nice trick will try to automatically grant admin + # consent and, if it does not succeed, it will print out the URL that the user + # needs to follow do grant manual admin consent. Wihtout this permission we + # won't be able to create Azure Integration on the user's Lacework account. + # + provisioner "local-exec" { + command = "az ad app permission admin-consent --id ${local.application_id} && echo SUCCESS!! || echo ERROR!!! Unable to grant admin consent, grant it manually by following the URL: https://login.microsoftonline.com/${local.tenant_id}/adminconsent?client_id=${local.application_id}" + } +} + +resource "azurerm_key_vault_access_policy" "default" { + count = var.create ? length(var.key_vault_ids) : 0 + key_vault_id = var.key_vault_ids[count.index] + object_id = local.service_principal_id + tenant_id = local.tenant_id + + key_permissions = [ + "List" + ] + secret_permissions = [ + "List" + ] +} + +data "azurerm_subscriptions" "available" {} +resource "azurerm_role_assignment" "grant_reader_role_to_subscriptions" { + count = var.create ? length(data.azurerm_subscriptions.available.subscriptions) : 0 + scope = "/subscriptions/${data.azurerm_subscriptions.available.subscriptions[count.index].subscription_id}" + + principal_id = azuread_service_principal.lacework[0].id + role_definition_name = "Reader" +} + +resource "random_password" "generator" { + count = var.create ? 1 : 0 + length = var.password_length +} + +resource "azuread_application_password" "client_secret" { + count = var.create ? 1 : 0 + application_object_id = local.service_principal_id + value = random_password.generator[count.index].result + end_date = "2299-12-31T01:02:03Z" + depends_on = [azuread_service_principal.lacework] +} diff --git a/azure/modules/ad_application/output.tf b/azure/modules/ad_application/output.tf new file mode 100644 index 0000000..fffd8e7 --- /dev/null +++ b/azure/modules/ad_application/output.tf @@ -0,0 +1,25 @@ +output "created" { + value = var.create + description = "Was the Active Directory Application created" +} + +output "application_password" { + value = local.application_password + description = "The Lacework AD Application password" + sensitive = true +} + +output "application_id" { + value = local.application_id + description = "The Lacework AD Application id" +} + +output "service_principal_id" { + value = local.service_principal_id + description = "The Lacework Service Principal id" +} + +output "tenant_id" { + value = local.tenant_id + description = "A Tenant ID used to configure the AD Application" +} diff --git a/azure/modules/ad_application/variables.tf b/azure/modules/ad_application/variables.tf new file mode 100644 index 0000000..e42f51e --- /dev/null +++ b/azure/modules/ad_application/variables.tf @@ -0,0 +1,40 @@ +variable "create" { + type = bool + default = true + description = "Set to false to prevent the module from creating any resources" +} + +variable "application_name" { + type = string + default = "lacework_security_audit" + description = "The name of the Azure Active Directory Applicaiton" +} + +variable "tenant_id" { + type = string + default = "" + description = "A Tenant ID different from the default defined inside the provider" +} + +variable "password_length" { + type = number + default = 30 + description = "The length of the Lacework AD Application password" +} + +# If some of the subscriptions use Key Vault services, we need to the +# Azure App to have access to each Key Vault used in your subscriptions. +variable "key_vault_ids" { + type = list(string) + description = "A list of Key Vault Ids used in your subscription for the Lacework AD App to have access to" + default = [] +} + +# TODO @afiune do we need this? +variable "application_identifier_uris" { + type = list(string) + description = "A list of user-defined URI(s) for the Lacework AD Application" + default = [ + "https://securityaudit.lacework.net" + ] +} diff --git a/azure/modules/config/examples/custom-config/main.tf b/azure/modules/config/examples/custom-config/main.tf new file mode 100644 index 0000000..c6ef67a --- /dev/null +++ b/azure/modules/config/examples/custom-config/main.tf @@ -0,0 +1,17 @@ +provider "azuread" {} + +provider "azurerm" { + features {} +} + +provider "lacework" {} + +module "az_config" { + source = "../../" + application_name = "lacework_custom_ad_application_name" + application_identifier_uris = ["https://account.lacework.net"] + key_vault_ids = ["vault-id-1", "vault-id-2", "vault-id-3", "vault-id-4"] + tenant_id = "123abc12-abcd-1234-abcd-abcd12340123" + lacework_integration_name = "a custom name" + password_lenght = 16 +} diff --git a/azure/modules/config/examples/default-config/main.tf b/azure/modules/config/examples/default-config/main.tf new file mode 100644 index 0000000..ac6e12d --- /dev/null +++ b/azure/modules/config/examples/default-config/main.tf @@ -0,0 +1,14 @@ +provider "azuread" {} + +provider "azurerm" { + features {} +} + +provider "lacework" { + #profile = "mini" +} + +module "az_config" { + source = "../../" + #application_identifier_uris = ["https://mini-ally.lacework.net"] +} diff --git a/azure/modules/config/main.tf b/azure/modules/config/main.tf new file mode 100644 index 0000000..23fffbf --- /dev/null +++ b/azure/modules/config/main.tf @@ -0,0 +1,30 @@ +locals { + application_id = var.use_existing_ad_application ? var.application_id : module.az_cfg_ad_application.application_id + application_password = var.use_existing_ad_application ? var.application_password : module.az_cfg_ad_application.application_password +} + +module "az_cfg_ad_application" { + source = "../ad_application" + create = var.use_existing_ad_application ? false : true + application_name = var.application_name + application_identifier_uris = var.application_identifier_uris + key_vault_ids = var.key_vault_ids + tenant_id = var.tenant_id + password_length = var.password_length +} + +# wait for X seconds for the Azure resources to be created +resource "time_sleep" "wait_time" { + create_duration = var.wait_time + depends_on = [module.az_cfg_ad_application] +} + +resource "lacework_integration_azure_cfg" "default" { + name = var.lacework_integration_name + tenant_id = module.az_cfg_ad_application.tenant_id + credentials { + client_id = local.application_id + client_secret = local.application_password + } + depends_on = [time_sleep.wait_time] +} diff --git a/azure/modules/config/output.tf b/azure/modules/config/output.tf new file mode 100644 index 0000000..dc20896 --- /dev/null +++ b/azure/modules/config/output.tf @@ -0,0 +1,20 @@ +output "application_password" { + value = local.application_password + description = "The Lacework AD Application password" + sensitive = true +} + +output "application_id" { + value = local.application_id + description = "The Lacework AD Application id" +} + +output "service_principal_id" { + value = module.az_cfg_ad_application.service_principal_id + description = "The Lacework Service Principal id" +} + +output "tenant_id" { + value = module.az_cfg_ad_application.tenant_id + description = "A Tenant ID used to configure the AD Application" +} diff --git a/azure/modules/config/variables.tf b/azure/modules/config/variables.tf new file mode 100644 index 0000000..ae77643 --- /dev/null +++ b/azure/modules/config/variables.tf @@ -0,0 +1,63 @@ +variable "application_name" { + type = string + default = "lacework_security_audit" + description = "The name of the Azure Active Directory Applicaiton" +} + +# TODO @afiune do we need this? +variable "application_identifier_uris" { + type = list(string) + description = "A list of user-defined URI(s) for the Lacework AD Application" + default = [ + "https://securityaudit.lacework.net" + ] +} + +# If some of the subscriptions use Key Vault services, we need to the +# Azure App to have access to each Key Vault used in your subscriptions. +variable "key_vault_ids" { + type = list(string) + description = "A list of Key Vault Ids used in your subscription for the Lacework AD App to have access to" + default = [] +} + +variable "tenant_id" { + type = string + default = "" + description = "A Tenant ID different from the default defined inside the provider" +} + +variable "password_length" { + type = number + default = 30 + description = "The length of the Lacework AD Application password" +} + +variable "lacework_integration_name" { + type = string + default = "TF config" +} + +variable "wait_time" { + type = string + default = "10s" + description = "Amount of time to wait before the Lacework resources are provisioned" +} + +variable "use_existing_ad_application" { + type = bool + default = false + description = "Set this to true to use an existing Active Directory Application" +} + +variable "application_id" { + type = string + default = "" + description = "The Active Directory Application id to use (required when use_existing_ad_application is set to true)" +} + +variable "application_password" { + type = string + default = "" + description = "The Active Directory Application password to use (required when use_existing_ad_application is set to true)" +} diff --git a/azure/variables.tf b/azure/variables.tf deleted file mode 100644 index b14b142..0000000 --- a/azure/variables.tf +++ /dev/null @@ -1,139 +0,0 @@ -//////////////////////////////// -// Lacework -// -variable "lacework_account" { - type = string -} - -variable "lacework_api_key" { - type = string -} - -variable "lacework_api_secret" { - type = string -} - -variable "lacework_integration_config_name" { - type = string - default = "Azure config" -} - -variable "lacework_integration_activitylog_name" { - type = string - default = "Azure Activity Log" -} - -//////////////////////////////// -// Azure Configuration - -variable "app_name" { - type = string - description = "Name of the Azure Active Directory App." - default = "LaceworkSAAudit" -} - -# TODO @afiune why do we need this? -variable "identifier_uris" { - type = list(string) - description = "URI's for app." - default = [ - "https://securityaudit.lacework.net" - ] -} - -# Must provide if the user has key vault -variable "key_vault_ids" { - type = list(string) - description = "Key Vault Ids." - default = [] -} - -variable "prefix" { - type = string - description = "The Prefix used for all resources in this example." - default = "dev" -} - -variable "location" { - type = string - description = "The Azure Region in which all resources in this example should be created." - default = "West US 2" -} - -variable "resource_group" { - type = string - description = "Resource group name to use." - default = null -} - -variable "storage" { - type = string - description = "Storage name to use for Activity Log." - default = null -} - -variable "storage_queue" { - type = string - description = "Storage queue name to use for Activity Log." - default = null -} - -variable "event_subscription" { - type = string - description = "Event subscription name to use for Activity Log." - default = null -} - -variable "log_profile" { - type = string - description = "Log profile name for Activity Log." - default = null -} - -variable "log_profile_locations" { - type = list(string) - description = "Locations for log profile." - default = [ - "eastasia", - "southeastasia", - "centralus", - "eastus", - "eastus2", - "westus", - "northcentralus", - "southcentralus", - "northeurope", - "westeurope", - "japanwest", - "japaneast", - "brazilsouth", - "australiaeast", - "australiasoutheast", - "southindia", - "centralindia", - "westindia", - "canadacentral", - "canadaeast", - "uksouth", - "ukwest", - "westcentralus", - "westus2", - "koreacentral", - "koreasouth", - "francecentral", - "francesouth", - "australiacentral", - "australiacentral2", - "uaecentral", - "uaenorth", - "southafricanorth", - "southafricawest", - "switzerlandnorth", - "switzerlandwest", - "germanynorth", - "germanywestcentral", - "norwaywest", - "norwayeast", - "global" - ] -} diff --git a/gcp/README.md b/gcp/README.md index 7607528..b56743e 100644 --- a/gcp/README.md +++ b/gcp/README.md @@ -9,6 +9,8 @@ Before using these modules you must meet the following requirements: - [GCP Service Account](https://cloud.google.com/iam/docs/service-accounts) - [Lacework API Key](https://support.lacework.com/hc/en-us/articles/360011403853-Generate-API-Access-Keys-and-Tokens) +Also recommend that the [Lacework CLI](https://github.com/lacework/go-sdk/wiki/CLI-Documentation) be installed and the `[default]` profile is associated with the applicable Lacework Account `api_key` and `api_secret` in `~/.lacework.toml` + ## GCP Organziation Level Integrations The following section covers how to integrate GCP configuration assessment and Audit Log for an entire Google Cloud Organization @@ -26,7 +28,7 @@ More information on how to download a GCP service account key can be found [here ### Usage -**IMPORTANT:** We use the `master` branch in source just as an example. In your code, *do NOT pin to master* because there may +**IMPORTANT:** We use the `master` branch in source just as an example. In your code, **do NOT pin to master** because there may be breaking changes between releases. Instead we recommend to pin to the release tag (e.g. `?ref=tags/v0.1.0`) of one of our [latest releases](https://github.com/lacework/terraform-provisioning/releases). diff --git a/scripts/ci_tests.sh b/scripts/ci_tests.sh index cbc5da5..4280fb9 100755 --- a/scripts/ci_tests.sh +++ b/scripts/ci_tests.sh @@ -17,6 +17,10 @@ MODULES=( gcp/modules/audit_log gcp/modules/config gcp/modules/service_account + azure/ + azure/modules/ad_application + azure/modules/config + azure/modules/activity_log ) TEST_CASES=( @@ -41,6 +45,8 @@ TEST_CASES=( #gcp/modules/audit_log/examples/existing-service-account-org-level-audit-log gcp/modules/audit_log/examples/organization-level-audit-log gcp/modules/audit_log/examples/project-level-audit-log + #azure/ + #azure/modules/ad_application/examples/default-config ) log() {