3.File.Storage/storage.tf (195 lines of code) (raw):
###################################################################################
# Storage (https://learn.microsoft.com/azure/storage/common/storage-introduction) #
###################################################################################
variable storageAccounts {
type = list(object({
enable = bool
name = string
type = string
tier = string
redundancy = string
enableHttpsOnly = bool
enableBlobNfsV3 = bool
enableLargeFileShare = bool
privateEndpointTypes = list(string)
blobContainers = list(object({
enable = bool
name = string
}))
fileShares = list(object({
enable = bool
name = string
sizeGB = number
accessTier = string
accessProtocol = string
}))
extendedZone = object({
enable = bool
})
}))
}
locals {
storageAccounts = [
for storageAccount in var.storageAccounts : merge(storageAccount, {
resourceGroup = {
name = var.resourceGroupName
location = storageAccount.extendedZone.enable && var.extendedZone.enable ? var.extendedZone.location : data.azurerm_virtual_network.studio.location
}
extendedZone = {
name = storageAccount.extendedZone.enable && var.extendedZone.enable ? var.extendedZone.name : null
}
storageAccount = {
id = "/subscriptions/${data.azurerm_subscription.current.subscription_id}/resourceGroups/${var.resourceGroupName}/providers/Microsoft.Storage/storageAccounts/${storageAccount.name}"
}
}) if storageAccount.enable
]
privateEndpoints = flatten([
for storageAccount in local.storageAccounts : [
for privateEndpointType in storageAccount.privateEndpointTypes : merge(storageAccount, {
key = "${storageAccount.name}-${privateEndpointType}"
type = privateEndpointType
dnsZone = {
id = "${data.azurerm_resource_group.dns.id}/providers/Microsoft.Network/privateDnsZones/privatelink.${privateEndpointType}.core.windows.net"
}
})
]
])
blobContainers = flatten([
for storageAccount in local.storageAccounts : [
for blobContainer in storageAccount.blobContainers : merge(storageAccount, blobContainer, {
key = "${storageAccount.name}-${blobContainer.name}"
}) if blobContainer.enable
]
])
fileShares = flatten([
for storageAccount in local.storageAccounts : [
for fileShare in storageAccount.fileShares : merge(storageAccount, fileShare, {
key = "${storageAccount.name}-${fileShare.name}"
}) if fileShare.enable
]
])
}
resource azurerm_role_assignment storage_blob_data_owner {
for_each = {
for storageAccount in local.storageAccounts : storageAccount.name => storageAccount
}
role_definition_name = "Storage Blob Data Owner" # https://learn.microsoft.com/azure/role-based-access-control/built-in-roles/storage#storage-blob-data-owner
principal_id = data.azurerm_client_config.current.object_id
scope = each.value.storageAccount.id
depends_on = [
azurerm_storage_account.studio
]
}
resource azurerm_role_assignment storage_blob_data_contributor {
for_each = {
for storageAccount in local.storageAccounts : storageAccount.name => storageAccount
}
role_definition_name = "Storage Blob Data Contributor" # https://learn.microsoft.com/azure/role-based-access-control/built-in-roles/storage#storage-blob-data-contributor
principal_id = data.azurerm_user_assigned_identity.studio.principal_id
scope = each.value.storageAccount.id
depends_on = [
azurerm_storage_account.studio
]
}
resource time_sleep storage_rbac {
for_each = {
for storageAccount in local.storageAccounts : storageAccount.name => storageAccount
}
create_duration = "30s"
depends_on = [
azurerm_role_assignment.storage_blob_data_owner,
azurerm_role_assignment.storage_blob_data_contributor
]
}
resource azurerm_storage_account studio {
for_each = {
for storageAccount in local.storageAccounts : storageAccount.name => storageAccount
}
name = each.value.name
resource_group_name = each.value.resourceGroup.name
location = each.value.resourceGroup.location
edge_zone = each.value.extendedZone.name
account_kind = each.value.type
account_tier = each.value.tier
account_replication_type = each.value.redundancy
https_traffic_only_enabled = each.value.enableHttpsOnly
is_hns_enabled = each.value.enableBlobNfsV3
nfsv3_enabled = each.value.enableBlobNfsV3
large_file_share_enabled = each.value.enableLargeFileShare ? true : null
local_user_enabled = false
shared_access_key_enabled = false
public_network_access_enabled = false
allow_nested_items_to_be_public = false
network_rules {
default_action = "Deny"
ip_rules = [
jsondecode(data.http.client_address.response_body).ip
]
dynamic private_link_access {
for_each = data.terraform_remote_state.core.outputs.defender.storage.malwareScanning.enable ? [1] : []
content {
endpoint_tenant_id = data.azurerm_client_config.current.tenant_id
endpoint_resource_id = "/subscriptions/${data.azurerm_subscription.current.subscription_id}/providers/Microsoft.Security/datascanners/storageDataScanner"
}
}
}
depends_on = [
azurerm_resource_group.storage
]
}
resource azurerm_storage_container core {
for_each = {
for blobContainer in local.blobContainers : blobContainer.key => blobContainer
}
name = each.value.name
storage_account_id = each.value.storageAccount.id
depends_on = [
time_sleep.storage_rbac
]
}
resource azurerm_storage_share core {
for_each = {
for fileShare in local.fileShares : fileShare.key => fileShare
}
name = each.value.name
access_tier = each.value.accessTier
enabled_protocol = each.value.accessProtocol
storage_account_id = each.value.storageAccount.id
quota = each.value.sizeGB
depends_on = [
azurerm_private_endpoint.storage
]
}
resource azurerm_private_endpoint storage {
for_each = {
for privateEndpoint in local.privateEndpoints : privateEndpoint.key => privateEndpoint if privateEndpoint.extendedZone.name == null
}
name = each.value.key
resource_group_name = each.value.resourceGroup.name
location = each.value.resourceGroup.location
# edge_zone = each.value.extendedZone.name != "" ? each.value.extendedZone.name : null
subnet_id = data.azurerm_subnet.storage.id
private_service_connection {
name = basename(each.value.storageAccount.id)
private_connection_resource_id = each.value.storageAccount.id
is_manual_connection = false
subresource_names = [
each.value.type
]
}
private_dns_zone_group {
name = basename(each.value.storageAccount.id)
private_dns_zone_ids = [
each.value.dnsZone.id
]
}
depends_on = [
azurerm_storage_account.studio
]
}
output storageAccounts {
value = [
for storageAccount in azurerm_storage_account.studio : {
name = storageAccount.name
location = storageAccount.primary_location
blobEndpoint = storageAccount.primary_blob_endpoint
fileEndpoint = storageAccount.primary_file_endpoint
}
]
}