Main.tf
provider "azurerm" {
features {}
}
locals {
access_map = {
owner_other_access = {
permissions_access = "---"
type = "other"
},
owner_group_access = {
permissions_access = "r-x"
type = "group"
},
owner_mask_access = {
permissions_access = "rwx"
type = "mask"
},
owner_user_access = {
permissions_access = "rwx"
type = "user"
}
}
default_map = {
owner_other_default = {
permissions_default = "---"
type = "other"
},
owner_group_default = {
permissions_default = "rwx"
type = "group"
},
owner_mask_default = {
permissions_default = "rwx"
type = "mask"
},
owner_user_default = {
permissions_default = "rwx"
type = "user"
}
}
}
resource "azurerm_storage_data_lake_gen2_filesystem" "this" {
for_each = var.storage_containers
name = each.value.sc_name
storage_account_id = each.value.storage_account_id
properties = {}
dynamic "ace" {
for_each = merge(local.access_map, jsondecode(each.value.acl_access))
iterator = item
content {
type = item.value.type
scope = "access"
permissions = item.value.permissions_access
id = lookup(item.value, "id", null)
}
}
dynamic "ace" {
for_each = merge(local.default_map, jsondecode(each.value.acl_default))
iterator = item
content {
type = item.value.type
scope = "default"
permissions = item.value.permissions_default
id = lookup(item.value, "id", null)
}
}
}
teraform.tfvars
storage_containers_fs = {
raw_fs_container = {
storage_account_id = "bronze_storage_account"
sc_name = "rawfs"
acl_access = "{\"owner_group_access\":{\"permissions_access\":\"r-x\",\"type\":\"group\",\"id\":\"3f97daxxxx-xxxxxxx-xxxxx-xxxxxx-xxxxxxxxx\",\"id\":\"f5509xxxxx-xxxxxxx-xxxxx-xxxxxx-xxxxxxxxx\"}}"
acl_default = "{\"owner_group_default\":{\"permissions_default\":\"rwx\",\"type\":\"group\",\"id\":\"3f97daxxxx-xxxxxxx-xxxxx-xxxxxx-xxxxxxxxx\",\"id\":\"f5509xxxx-xxxxxxx-xxxxx-xxxxxx-xxxxxxxxx\"}}"
}
}
varaibles.tf
variable "storage_containers_fs" {
description = "Storage Containers settings"
type = map(object({
storage_account_id = string
sc_name = string
acl_access = string
acl_default = string
}))
}
My problem with this code is: When deploying for the very first time, this code works and creates a private container with ACL
inside, assigning the correct rights to the two identities, in this case two groups, as seen above
When deploying this code again with a new group added to thte existing ones, the code fails by trying to replace the first group in the list with the new one added.
The new tfvars
will look like this:
storage_containers_fs = {
raw_fs_container = {
storage_account_id = "bronze_storage_account"
sc_name = "rawfs"
acl_access = "{\"owner_group_access\":{\"permissions_access\":\"r-x\",\"type\":\"group\",\"id\":\"3f97daxxxx-xxxxxxx-xxxxx-xxxxxx-xxxxxxxxx\",\"id\":\"f5509xxxx-xxxxxxx-xxxxx-xxxxxx-xxxxxxxxx\",\"id\":\"deb25xxxxx-xxxxxxx-xxxxx-xxxxxx-xxxxxxxxx\"}}"
acl_default = "{\"owner_group_default\":{\"permissions_default\":\"rwx\",\"type\":\"group\",\"id\":\"3f97daxxxx-xxxxxxx-xxxxx-xxxxxx-xxxxxxxxx\",\"id\":\"f5509xxxx-xxxxxxx-xxxxx-xxxxxx-xxxxxxxxx\"}}"
}
}
This is the output from apply
:
Terraform will perform the following actions:
# module.az_bronze_storage_containers_fs.azurerm_storage_data_lake_gen2_filesystem.this["raw_fs_container"] will be updated in-place
~ resource "azurerm_storage_data_lake_gen2_filesystem" "this" {
id = "https://xxxxxxxxxxxxxxxxx.dfs.core.windows.net/rawfs"
name = "rawfs"
# (4 unchanged attributes hidden)
- ace {
- permissions = "---" -> null
- scope = "access" -> null
- type = "other" -> null
}
- ace {
- permissions = "---" -> null
- scope = "default" -> null
- type = "other" -> null
}
- ace {
- permissions = "rwx" -> null
- scope = "access" -> null
- type = "mask" -> null
}
- ace {
- permissions = "rwx" -> null
- scope = "access" -> null
- type = "user" -> null
}
- ace {
- permissions = "rwx" -> null
- scope = "default" -> null
- type = "mask" -> null
}
- ace {
- permissions = "rwx" -> null
- scope = "default" -> null
- type = "user" -> null
}
- ace {
- id = "3f97xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx" -> null
- permissions = "r-x" -> null
- scope = "access" -> null
- type = "group" -> null
}
+ ace {
+ id = "deb25xxx-xxxx-xxxx-xxxx-xxxxxxxxxxx"
+ permissions = "r-x"
+ scope = "access"
+ type = "group"
}
+ ace {
+ permissions = "---"
+ scope = "access"
+ type = "other"
}
+ ace {
+ permissions = "---"
+ scope = "default"
+ type = "other"
}
+ ace {
+ permissions = "rwx"
+ scope = "access"
+ type = "mask"
}
+ ace {
+ permissions = "rwx"
+ scope = "access"
+ type = "user"
}
+ ace {
+ permissions = "rwx"
+ scope = "default"
+ type = "mask"
}
+ ace {
+ permissions = "rwx"
+ scope = "default"
+ type = "user"
}
# (1 unchanged block hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
module.az_bronze_storage_containers_fs.azurerm_storage_data_lake_gen2_filesystem.this["raw_fs_container"]: Modifying... [id=https://xxxxxxxxxxxxxxxxx.dfs.core.windows.net/rawfs]
╷
│ Error: setting access control for root path in File System "rawfs" in Storage Account "xxxxxxxxxxxxxxxxx": datalakestore.Client#SetAccessControl: Failure responding to request: StatusCode=403 -- Original Error: autorest/azure: Service returned an error. Status=403 Code="AuthorizationPermissionMismatch" Message="This request is not authorized to perform this operation using this permission.\nRequestId:e59de7e1-b01f-0066-41cd-3f5884000000\nTime:2024-01-05T11:48:36.0364932Z"
│
│ with module.az_bronze_storage_containers_fs.azurerm_storage_data_lake_gen2_filesystem.this["raw_fs_container"],
│ on ..\templates\az-storage-filesystem\main.tf line 42, in resource "azurerm_storage_data_lake_gen2_filesystem" "this":
│ 42: resource "azurerm_storage_data_lake_gen2_filesystem" "this" {
Not sure why this doesn't work.
Ideally is to add a new group without removing the existing one (first problem) AND can we make this template use group names instead of UUIDs
in the tfvars
(second problem)? Maybe using data.azuread_users
, data.azuread_groups
, data.azuread_serviceprincipals
? Hardcoding IDs in the tfvars doesn't seem like a good idea. I would personally add the group name instead of the ID and let the template resolve the ID for me.
I was expecting a new identity to be added instead of replacing an existing one.
Ideally is to add a new group without removing the existing one (first problem).
To modify the existing container , you may need Storage Blob Data Owner role. Follow the Ms doc for more details
can we make this template use group names instead of
UUIDs
in thetfvars
(second problem)? Maybe usingdata.azuread_users
,data.azuread_groups
,data.azuread_serviceprincipals
? Hardcoding IDs in the tfvars doesn't seem like a good idea.
If you create containers using .tfvars, it accepts an ID, not a name. However, you can use the code below to create a container without hardcoding the group ID by using a data block
terraform.tfvars
storage_containers = {
container1 = {
storage_account_id = ""
sc_name = "container1"
acl_access = "{\"owner_user_access\":{\"permissions_access\":\"rwx\",\"type\":\"user\"},\"owner_group_access\":{\"permissions_access\":\"r-x\",\"type\":\"group\",\"id\":\"data.azuread_group.example.id\"},\"owner_other_access\":{\"permissions_access\":\"---\",\"type\":\"other\"},\"owner_mask_access\":{\"permissions_access\":\"rwx\",\"type\":\"mask\"}}"
acl_default = "{\"owner_user_default\":{\"permissions_default\":\"rwx\",\"type\":\"user\"},\"owner_group_default\":{\"permissions_default\":\"rwx\",\"type\":\"group\",\"id\":\"data.azuread_group.example.id\"},\"owner_other_default\":{\"permissions_default\":\"---\",\"type\":\"other\"},\"owner_mask_default\":{\"permissions_default\":\"rwx\",\"type\":\"mask\"}}"
},
container2 = {
storage_account_id = ""
sc_name = "container2"
acl_access = "{\"owner_user_access\":{\"permissions_access\":\"rwx\",\"type\":\"user\"},\"owner_group_access\":{\"permissions_access\":\"r-x\",\"type\":\"group\",\"id\":\"Group-ID\"},\"owner_other_access\":{\"permissions_access\":\"---\",\"type\":\"other\"},\"owner_mask_access\":{\"permissions_access\":\"rwx\",\"type\":\"mask\"}}"
acl_default = "{\"owner_user_default\":{\"permissions_default\":\"rwx\",\"type\":\"user\"},\"owner_group_default\":{\"permissions_default\":\"rwx\",\"type\":\"group\",\"id\":\"Group-ID\"},\"owner_other_default\":{\"permissions_default\":\"---\",\"type\":\"other\"},\"owner_mask_default\":{\"permissions_default\":\"rwx\",\"type\":\"mask\"}}"
}
}
Here is the updated code to create an containers without .tfvars file.
provider "azurerm" {
features {}
}
locals {
access_map = {
container1 = {
permissions_access = "rwx"
type = "group"
},
container2 = {
permissions_access = "rwx"
type = "user"
}
}
default_map = {
group = {
permissions_default = "rwx"
type = "group"
},
user = {
permissions_default = "rwx"
type = "user"
},
}
}
data "azuread_group" "example" {
display_name = "Azure-AD-Group-Name"
}
data "azurerm_storage_account" "example" {
name = "storage-account-name"
resource_group_name = "RG-name"
}
resource "azurerm_storage_data_lake_gen2_filesystem" "example" {
for_each = local.access_map
name = each.key
storage_account_id = data.azurerm_storage_account.example.id
dynamic "ace" {
for_each = [data.azuread_group.example.id]
content {
id = ace.value
permissions = local.access_map[each.key].permissions_access
scope = "access"
type = local.access_map[each.key].type
}
}
dynamic "ace" {
for_each = local.default_map
content {
type = ace.key
scope = "default"
permissions = ace.value.permissions_default
id = data.azuread_group.example.id
}
}
}
Output: