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
1 change: 1 addition & 0 deletions infrastructure/environments/dev/variables.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ AZURE_SUBSCRIPTION="Breast Screening - NBSS Extraction - Dev"
HUB_SUBSCRIPTION="Digital Screening DToS - DevOps"
ENABLE_SOFT_DELETE=false
TERRAFORM_MODULES_REF=main
HUB=dev
92 changes: 77 additions & 15 deletions infrastructure/terraform/defender.tf
Original file line number Diff line number Diff line change
@@ -1,34 +1,96 @@
resource "azapi_resource" "defender_storage" {
for_each = local.defender_storage_accounts
locals {
defender_upload_storage_account_name = substr(replace("sa${var.app_short_name}${var.environment}defender", "/[^0-9a-z]/", ""), 0, 24)

defender_containers = [
"clean-scans",
"quarantine-scans"
]

defender_target_storage_accounts = {
(local.upload_storage_account_name) = azurerm_storage_account.upload.id
}
}

# Configure Defender for all trust upload storage accounts
# Use "update" to modify existing Defender for Storage settings rather than creating new ones
resource "azapi_update_resource" "defender_settings" {
for_each = local.defender_target_storage_accounts

type = "Microsoft.Security/defenderForStorageSettings@2026-01-01-preview"
name = "current"
parent_id = each.value
resource_id = "${each.value}/providers/Microsoft.Security/defenderForStorageSettings/current"
Comment thread
micjustus-nc marked this conversation as resolved.

body = {
properties = {
isEnabled = var.scan_is_enabled
isEnabled = var.scan_is_enabled

# only provide if the storage accounts absolutely must have their own settings
overrideSubscriptionLevelSettings = var.override_subscription_settings_enabled
# only provide if the storage accounts absolutely must have their own settings
overrideSubscriptionLevelSettings = var.override_subscription_settings_enabled

malwareScanning = {
sensitiveDataDiscovery = {
isEnabled = var.sensitive_data_discovery_enabled && var.scan_is_enabled
}

malwareScanning = {
blobScanResultsOptions = "BlobIndexTags"
onUpload = {
isEnabled = var.malware_scanning_on_upload_enabled && var.scan_is_enabled
capGBPerMonth = var.malware_scanning_on_upload_cap_gb_per_month
}
}

sensitiveDataDiscovery = {
isEnabled = var.sensitive_data_discovery_enabled && var.scan_is_enabled
}
}
}
}

locals {
defender_storage_accounts = {
upload = azurerm_storage_account.upload.id
# for the incoming function that triggers a move from the upload container to the defender storage account containers
# we need to ensure that the defender storage accounts are properly configured and accessible
# Since Defender storage accounts are not publicly accessible, we don't need to worry about write-only
# permissions as we do with the client landing containers

resource "azurerm_storage_account" "defender_storage_account" {
name = local.defender_upload_storage_account_name
resource_group_name = azurerm_resource_group.deploy_resource_group.name
location = azurerm_resource_group.deploy_resource_group.location

account_tier = "Standard"
account_replication_type = "LRS"
account_kind = "StorageV2"

allow_nested_items_to_be_public = false
cross_tenant_replication_enabled = false
default_to_oauth_authentication = true
https_traffic_only_enabled = true
infrastructure_encryption_enabled = true
min_tls_version = "TLS1_2"

public_network_access_enabled = false
Comment thread
micjustus-nc marked this conversation as resolved.

# The intention for the storage account is to provide Shared Key access and also Entra ID authentication.
shared_access_key_enabled = true
}

resource "azurerm_storage_container" "defender_containers" {
for_each = toset(local.defender_containers)
name = each.key
storage_account_id = azurerm_storage_account.defender_storage_account.id
container_access_type = "private"
}

resource "azurerm_private_endpoint" "defender_storage_blob" {
provider = azurerm.hub
name = "${local.defender_upload_storage_account_name}-pep"
location = data.azurerm_resource_group.hub_private_endpoint.location
resource_group_name = data.azurerm_resource_group.hub_private_endpoint.name
subnet_id = data.azurerm_subnet.hub_private_endpoint.id

private_service_connection {
name = "${local.defender_upload_storage_account_name}-blob"
private_connection_resource_id = azurerm_storage_account.defender_storage_account.id
subresource_names = ["blob"]
is_manual_connection = false
}

private_dns_zone_group {
name = "${local.defender_upload_storage_account_name}-blob-dns"
private_dns_zone_ids = [data.azurerm_private_dns_zone.blob.id]
}
}
6 changes: 3 additions & 3 deletions infrastructure/terraform/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module "shared_config" {
application = var.app_short_name
}

locals{
resource_group_name = "rg-${var.app_short_name}-${var.env_config}-uks"
region = "uksouth"
locals {
resource_group_name = "rg-${var.app_short_name}-${var.env_config}-uks"
region = "uksouth"
}
41 changes: 41 additions & 0 deletions infrastructure/terraform/networking.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
locals {
hub_private_endpoint_resource_group_name = "rg-hub-${var.hub}-uks-hub-private-endpoints"
hub_private_dns_zone_resource_group_name = "rg-hub-${var.hub}-uks-private-dns-zones"
hub_network_resource_group_name = "rg-hub-${var.hub}-uks-hub-networking"
hub_vnet_name = "VNET-${upper(var.hub)}-UKS-HUB"
hub_private_endpoint_subnet_name = "SN-${upper(var.hub)}-UKS-HUB-pep"
}

data "azurerm_resource_group" "hub_private_endpoint" {
provider = azurerm.hub
name = local.hub_private_endpoint_resource_group_name
}

data "azurerm_resource_group" "hub_private_dns_zones" {
provider = azurerm.hub
name = local.hub_private_dns_zone_resource_group_name
}

data "azurerm_resource_group" "hub_network" {
provider = azurerm.hub
name = local.hub_network_resource_group_name
}

data "azurerm_virtual_network" "hub" {
provider = azurerm.hub
name = local.hub_vnet_name
resource_group_name = data.azurerm_resource_group.hub_network.name
}

data "azurerm_subnet" "hub_private_endpoint" {
provider = azurerm.hub
name = local.hub_private_endpoint_subnet_name
virtual_network_name = data.azurerm_virtual_network.hub.name
resource_group_name = data.azurerm_resource_group.hub_network.name
}

data "azurerm_private_dns_zone" "blob" {
provider = azurerm.hub
name = var.storage_blob_private_dns_zone_name
resource_group_name = "rg-hub-${var.hub}-uks-private-dns-zones"
}
26 changes: 23 additions & 3 deletions infrastructure/terraform/output.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
output "upload_container_urls" {
value = {
locals {
upload_container_details = {
for container_key, container in azurerm_storage_container.bso :
container_key => "${azurerm_storage_account.upload.primary_blob_endpoint}${container.name}"
container_key => {
endpoint = container.id
storage_account_id = container.storage_account_id
}
}

upload_container_urls = {
for container_key, container in local.upload_container_details :
container_key => container.endpoint
}
}

output "upload_container_urls" {
value = local.upload_container_urls
Comment thread
micjustus-nc marked this conversation as resolved.
}

output "defender_storage_account_id" {
value = azurerm_storage_account.defender_storage_account.id
}

output "defender_storage_private_endpoint_id" {
value = azurerm_private_endpoint.defender_storage_blob.id
}
18 changes: 11 additions & 7 deletions infrastructure/terraform/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ variable "environment" {
variable "hub" {
description = "Hub name (dev or prod)"
type = string
validation {
condition = contains(["dev", "prod"], var.hub)
error_message = "Hub must be either 'dev' or 'prod'"
}
}

variable "hub_subscription_id"{
Expand All @@ -28,12 +32,6 @@ variable "arm_subscription_id" {
type = string
}

variable "enable_defender_for_storage" {
description = "Enable Microsoft Defender for Storage for the configured storage account and containers"
type = bool
default = false
}

# defender for storage variables

variable "override_subscription_settings_enabled" {
Expand All @@ -45,7 +43,7 @@ variable "override_subscription_settings_enabled" {
variable "malware_scanning_on_upload_enabled" {
description = "Enable malware scanning on upload for Microsoft Defender for Storage"
type = bool
default = true
default = false
Comment thread
micjustus-nc marked this conversation as resolved.
}

variable "malware_scanning_on_upload_cap_gb_per_month" {
Expand All @@ -65,3 +63,9 @@ variable "scan_is_enabled" {
type = bool
default = true
}

variable "storage_blob_private_dns_zone_name" {
description = "Private DNS zone name for storage blob private endpoints"
type = string
default = "privatelink.blob.core.windows.net"
}
Loading