8000
10BC0
Skip to content

Latest commit

Β 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

☁️ Azure Storage Container Terraform Module

A standalone module that provisions a single Azure blob storage container, private by default, inside a storage account you already own. Targets hashicorp/azurerm ~> 4.0.

Terraform azurerm Module Type Resources

🧩 Overview

  • πŸ“¦ Creates one azurerm_storage_container (named this) inside a storage account supplied by storage_account_id.
  • πŸ”’ Defaults the container to private β€” no anonymous read access to blobs or the container listing.
  • 🏷️ Accepts optional container metadata (key/value pairs), updatable in place.
  • πŸ” Exposes an optional default_encryption_scope and its encryption_scope_override_enabled guard for scope-narrowed encryption at rest.
  • ⏱️ Carries the universal timeouts tail; it does not carry tags (the resource type has no tag support).

πŸ’‘ Why it matters: A container is the data-plane boundary where blob access and encryption scope are decided. Getting the default wrong exposes data to the public internet. This module makes the private, non-anonymous container the zero-configuration outcome and forces every relaxation to be typed explicitly and reviewed.

❀️ Support this project

If this module saves you time, please consider supporting it:

πŸ—ΊοΈ Where this fits in the family

graph LR
  rg["terraform-azurerm-resource-group"]
  sa["terraform-azurerm-storage-account"]
  this["terraform-azurerm-storage-container"]
  ra["terraform-azurerm-role-assignments"]
  pe["terraform-azurerm-private-endpoint"]

  rg -->|"resource_group_name"| sa
  sa -->|"storage_account_id"| this
  this -->|"scope for RBAC"| ra
  sa -->|"private connectivity"| pe

  classDef me fill:#0078D4,stroke:#004578,color:#ffffff;
  classDef keystone fill:#004578,stroke:#002E4D,color:#ffffff;
  classDef sib fill:#F0F4F8,stroke:#B0BEC5,color:#1A1A1A;

  class this me;
  class sa keystone;
  class rg,ra,pe sib;
Loading

This module owns only the container. The parent storage account (its keystone) is created by a sibling module and passed in by id; RBAC data-plane grants and private connectivity are the concern of their own sibling modules and consume this container by id.

🧬 What this module builds

graph LR
  subgraph inputs["Inputs"]
    name["name"]
    said["storage_account_id"]
    cat["container_access_type = private"]
    md["metadata"]
    des["default_encryption_scope"]
    eso["encryption_scope_override_enabled"]
  end

  this["azurerm_storage_container.this"]

  subgraph outputs["Outputs"]
    oid["id"]
    onm["name"]
    ohip["has_immutability_policy"]
    ohlh["has_legal_hold"]
  end

  name -->|"required"| this
  said -->|"required"| this
  cat -->|"private by default"| this
  md -->|"optional"| this
  des -->|"optional"| this
  eso -->|"optional"| this
  this -->|"emits"| oid
  this -->|"emits"| onm
  this -->|"emits"| ohip
  this -->|"emits"| ohlh

  classDef me fill:#0078D4,stroke:#004578,color:#ffffff;
  class this me;
Loading

Resource inventory

Resource Name Count Role
azurerm_storage_container this 1 The blob container; the module's single keystone resource.

βœ… Provider / Versions

Requirement Value
Terraform floor >= 1.12.0
Provider hashicorp/azurerm, pinned ~> 4.0
Provider block None in this module β€” the caller configures provider "azurerm", including the mandatory features {} block, auth, and subscription.

Schema notes that bite (verified against the live provider schema):

  • name and storage_account_id are force-new β€” changing either replaces the container and destroys its contents.
  • default_encryption_scope and encryption_scope_override_enabled are force-new β€” set them at creation; changing them later replaces the container.
  • The legacy account-name argument is deprecated in the pinned provider line (slated for removal in the next major line). This module exposes only storage_account_id; supply the account's Resource ID, not its name.
  • The container's id now carries the Resource Manager ID. The separate resource-manager-ID attribute is deprecated in the pinned provider line, so this module emits the ARM identifier through id and does not surface the deprecated attribute.
  • container_access_type values blob and container only take effect when the parent account permits public blob access (allow_nested_items_to_be_public = true), which a hardened account disables by default.
  • metadata is computed as well as optional; supplying an empty map (the default) means "no user metadata" and avoids perpetual diffs.

πŸ”‘ Required Azure RBAC Roles / Permissions

  • Management plane (create/update/delete the container definition): Storage Account Contributor on the target storage account, or a custom role granting Microsoft.Storage/storageAccounts/blobServices/containers/* at that scope.
  • Data plane (read/write blobs inside the container): assign a Storage Blob Data role to the consuming identity at the account or container scope, least-privilege first:
    • Storage Blob Data Reader β€” read/list blobs.
    • Storage Blob Data Contributor β€” read/write/delete blobs.
    • Storage Blob Data Owner β€” full control including POSIX ACLs on Data Lake Gen2.

These two planes are independent: holding a management role does not grant blob data access, and vice versa.

Azure Prerequisites

  • The Microsoft.Storage resource provider registered on the target subscription.
  • The parent storage account already exists (its id is an input); this module does not create it.
  • For blob / container access types, the parent account must permit public blob access (allow_nested_items_to_be_public = true).
  • Any named encryption scope referenced by default_encryption_scope must already exist on the parent account.
  • The caller configures provider "azurerm" { features {} }, auth, and subscription.

πŸ“ Module Structure

terraform-azurerm-storage-container/
β”œβ”€β”€ providers.tf     # required_version >= 1.12.0; azurerm ~> 4.0; no provider block
β”œβ”€β”€ variables.tf     # deeply-typed inputs; container_access_type enum; timeouts tail (no tags)
β”œβ”€β”€ main.tf          # azurerm_storage_container.this; dynamic timeouts; try() on optionals
β”œβ”€β”€ outputs.tf       # id first, then name, has_immutability_policy, has_legal_hold
β”œβ”€β”€ README.md        # this document
β”œβ”€β”€ SCOPE.md         # the cross-module contract
β”œβ”€β”€ LICENSE          # MIT, Copyright (c) 2026 Casey Wood
└── .gitignore       # canonical library ignore set

βš™οΈ Quick Start

provider "azurerm" {
  features {}
}

module "app_data" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-container.git?ref=v1.0.0"

  name               = "app-data"
  storage_account_id = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-platform/providers/Microsoft.Storage/storageAccounts/stplatformdata01"
  # container_access_type defaults to "private" β€” no anonymous access.
}

ℹ️ The caller owns provider configuration: authentication, subscription, and the mandatory features {} block. The module declares no provider {} block and no credential/subscription variables. Always pin ?ref=v1.0.0 β€” never a branch.

πŸ”Œ Cross-Module Contract

Consumes

Input Type Source module
storage_account_id string terraform-azurerm-storage-account (id)

Emits

Output Description
id The Azure Resource Manager ID of the container (emitted first).
name The container name.
has_immutability_policy Whether an immutability policy is configured β€” not whether it is locked.
has_legal_hold Whether a legal hold is configured.

πŸ“š Example Library

1 Β· Minimal private container (secure default)
module "logs" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-container.git?ref=v1.0.0"

  name               = "app-logs"
  storage_account_id = var.storage_account_id
}

πŸ”’ The empty call yields a private container: no anonymous read access to blobs or the container listing.

2 Β· Container with metadata
module "invoices" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-container.git?ref=v1.0.0"

  name               = "invoices"
  storage_account_id = var.storage_account_id

  metadata = {
    owner      = "finance-platform"
    dataclass  = "internal"
    retention  = "7y"
  }
}

πŸ’‘ Metadata keys are validated by the provider as ^([a-z_]{1}[a-z0-9_]{1,})$ β€” lower-case only, at least two characters, and C# keywords are rejected. The provider does not fold case for you: Owner is rejected at plan rather than stored as owner. Metadata is updatable in place, so editing it does not replace the container.

3 Β· Anonymous blob-level public read
module "public_assets" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-container.git?ref=v1.0.0"

  name                  = "public-assets"
  storage_account_id    = var.storage_account_id
  container_access_type = "blob"
}

⚠️ blob grants anonymous read access to individual blobs (not the container listing). It only takes effect if the parent account sets allow_nested_items_to_be_public = true, which a hardened account disables by default.

4 Β· Anonymous container-level public read
module "public_catalog" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-container.git?ref=v1.0.0"

  name                  = "public-catalog"
  storage_account_id    = var.storage_account_id
  container_access_type = "container"
}

⚠️ container additionally exposes the blob listing anonymously. Use it only for genuinely public catalogs, and confirm the account permits public blob access.

5 Β· Default encryption scope
module "scoped_data" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-container.git?ref=v1.0.0"

  name                     = "scoped-data"
  storage_account_id       = var.storage_account_id
  default_encryption_scope = "cmkfinancescope"
}

πŸ”’ Data at rest is always encrypted regardless of this setting; a default encryption scope narrows the key used for this container's blobs to a scope defined on the parent account. This field is force-new.

6 Β· Encryption scope allowing per-blob overrides
module "mixed_scope_data" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-container.git?ref=v1.0.0"

  name                              = "mixed-scope-data"
  storage_account_id                = var.storage_account_id
  default_encryption_scope          = "cmkfinancescope"
  encryption_scope_override_enabled = true
}

πŸ”΄ Read the direction of this flag carefully β€” it is the opposite of what the name suggests. encryption_scope_override_enabled = true permits a blob to be uploaded under a different encryption scope than the container's default. It maps to the API's DenyEncryptionScopeOverride = false, and the provider's own source comments that defaulting it to false "would be preferable here, but the API defaults this to true when unspecified". So true is the PERMISSIVE value and false is the one that pins every blob to the container's scope. This example sets true deliberately, to show the mixed-scope case. The flag is meaningful only alongside default_encryption_scope, and both are force-new.

7 Β· Custom operation timeouts
module "slow_container" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-container.git?ref=v1.0.0"

  name               = "bulk-ingest"
  storage_account_id = var.storage_account_id

  timeouts = {
    create = "30m"
    delete = "30m"
  }
}

πŸ’‘ All four timeouts (create, read, update, delete) are optional Go duration strings; omit the ones you do not need.

8 Β· Static-website content container ($web)
module "web_root" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-container.git?ref=v1.0.0"

  name                  = "$web"
  storage_account_id    = var.storage_account_id
  container_access_type = "private"
}

πŸ”’ The reserved $web container backs the storage account's static-website feature. private is still the right value here, but be clear about what it does and does not do. Microsoft: "Disallowing anonymous access for a storage account does not affect any static websites hosted in that storage account. The $web container is always publicly accessible." Changing the container's access level alters anonymous access to the blob endpoint (.blob.core.windows.net/$web/...) and has no effect on the static-website endpoint (.z##.web.core.windows.net), which serves every file by anonymous read whatever this setting says. So private closes the blob path and nothing more β€” treat everything you put in $web as public, and put access control in front of the website endpoint if you need it.

9 Β· The reserved root container (`$root`)
module "storage_root" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-container.git?ref=v1.0.0"

  name               = "$root"
  storage_account_id = var.storage_account_id
}

πŸ”’ $root lets a blob be addressed directly under the account host, with no container segment in the URL β€” useful for a file that has to sit at the top of the namespace, such as crossdomain.xml. It stays private here; nothing about the reserved name relaxes access.

⚠️ $root and $web are the ONLY reserved names this resource accepts. The provider's validator is ^\$root$|^\$web$|^[0-9a-z-]+$, so $logs is rejected at plan β€” the leading $ fails the general pattern and there is no $logs alternative. That is not a gap in the module: classic storage-analytics logging is enabled on the storage account, and the service creates and owns $logs itself. There is nothing here to declare.

10 Β· Many containers with for_each at scale
locals {
  containers = ["raw", "curated", "sandbox", "archive"]
}

module "lake_zones" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-container.git?ref=v1.0.0"

  for_each = toset(local.containers)

  name               = each.value
  storage_account_id = var.storage_account_id
}

πŸ’‘ Keying for_each on a stable set means adding or removing one zone never re-creates the others.

11 Β· Per-container access type and metadata via a map
locals {
  containers = {
    raw = {
      access   = "private"
      metadata = { zone = "raw" }
    }
    published = {
      access   = "blob"
      metadata = { zone = "published" }
    }
  }
}

module "zoned" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-container.git?ref=v1.0.0"

  for_each = local.containers

  name                  = each.key
  storage_account_id    = var.storage_account_id
  container_access_type = each.value.access
  metadata              = each.value.metadata
}

⚠️ The published zone uses blob access β€” it exposes blobs anonymously only if the parent account permits public blob access.

12 Β· Data Lake Gen2 medallion layout
module "medallion" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-container.git?ref=v1.0.0"

  for_each = toset(["bronze", "silver", "gold"])

  name               = each.value
  storage_account_id = var.storage_account_id

  metadata = {
    layer = each.value
  }
}

ℹ️ On a hierarchical-namespace (Data Lake Gen2) account, containers are filesystems; the same resource models both, and data-plane access is still governed by Storage Blob Data roles.

13 Β· Wiring a sibling storage-account output
module "storage" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-account.git?ref=v1.0.0"

  name                = "stplatformdata01"
  resource_group_name = var.resource_group_name
  location            = var.location
}

module "app_data" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-container.git?ref=v1.0.0"

  name               = "app-data"
  storage_account_id = module.storage.id
}

πŸ’‘ Referencing module.storage.id makes Terraform create the account before the container without any depends_on.

14 Β· Granting data-plane access on the created container
module "app_data" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-container.git?ref=v1.0.0"

  name               = "app-data"
  storage_account_id = module.storage.id
}

module "blob_access" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-role-assignments.git?ref=v1.0.0"

  scope = module.app_data.id

  role_assignments = {
    app_writer = {
      scope                = module.app_data.id
      role_definition_name = "Storage Blob Data Contributor"
      principal_id         = var.app_identity_principal_id
    }
  }
}

πŸ”’ Scope the blob data role to the container id, not the whole account, when only one container needs access β€” least privilege at the smallest scope.

15 Β· πŸ—οΈ End-to-end composition
provider "azurerm" {
  features {}
}

module "rg" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-resource-group.git?ref=v1.0.0"

  name     = "rg-platform-data"
  location = "eastus2"
}

module "storage" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-account.git?ref=v1.0.0"

  name                = "stplatformdata01"
  resource_group_name = module.rg.name
  location            = module.rg.location
  # secure defaults from the storage-account module: public access off,
  # shared-key auth off, TLS1_2 floor, infra encryption on.
}

module "app_data" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-storage-container.git?ref=v1.0.0"

  name               = "app-data"
  storage_account_id = module.storage.id

  metadata = {
    owner = "platform-team"
  }
}

module "blob_access" {
  source = "git::https://github.com/microsoftexpert/terraform-azurerm-role-assignments.git?ref=v1.0.0"

  scope = module.app_data.id

  role_assignments = {
    app_writer = {
      scope                = module.app_data.id
      role_definition_name = "Storage Blob Data Contributor"
      principal_id         = var.app_identity_principal_id
    }
  }
}

output "container_id" {
  value = module.app_data.id
}

πŸ’‘ The chain wires resource group β†’ storage account β†’ container β†’ data-plane role assignment entirely through module outputs. Ordering is implicit: each module references the previous one's id or name, so no depends_on is required.

πŸ“₯ Inputs

Identity (required)

Name Type Description
name string Container name. The provider's validator is `^$root$
storage_account_id string Resource ID of the owning storage account. Force-new.

Access, metadata, and encryption (optional)

Name Type Default Description
container_access_type string "private" Anonymous access level: private, blob, or container.
metadata map(string) {} Key/value metadata; updatable in place.
default_encryption_scope string null Named account encryption scope applied to blobs. Force-new.
encryption_scope_override_enabled bool null PERMIT a blob to use a different scope than the container default β€” true allows the override, false pins every blob to the container's scope. The provider default is true (permissive); this module leaves it unset and renders it only when default_encryption_scope is also set, which is what the provider's RequiredWith demands. Force-new.

Universal tail

Name Type Default Description
timeouts object({ create, read, update, delete }) null Optional per-operation timeouts (Go duration strings).

ℹ️ This resource type does not support Azure resource tags, so the module intentionally omits a tags variable.

Full input schemas
variable "name" {
  type = string
}

variable "storage_account_id" {
  type = string
}

variable "container_access_type" {
  type    = string
  default = "private"
  validation {
    condition     = contains(["private", "blob", "container"], var.container_access_type)
    error_message = "container_access_type must be one of: private, blob, container."
  }
}

variable "metadata" {
  type    = map(string)
  default = {}
}

variable "default_encryption_scope" {
  type    = string
  default = null
}

variable "encryption_scope_override_enabled" {
  type    = bool
  default = null
}

variable "timeouts" {
  type = object({
    create = optional(string)
    read   = optional(string)
    update = optional(string)
    delete = optional(string)
  })
  default = null
}

🧾 Outputs

Output Description Kind
id The Azure Resource Manager ID of the blob container Passthrough
name The name of the blob container Passthrough
storage_account_id The Azure Resource Manager ID of the storage account that owns this container, as read back by the provider Passthrough
url The container's DATA-PLANE URL, in the form https://ACCOUNT.blob.core.windows.net/CONTAINER Passthrough
resource_type The Azure Resource Manager resource type of this record, for composing role definitions, policy assignments and diagnostic settings without parsing the Resource ID Derived
container_access_type The effective anonymous-access level on the container as read back by the provider: private, blob or container Passthrough
anonymous_read_permitted True when the container itself grants anonymous read access to its blobs (the access level is blob or container) Passthrough
anonymous_listing_permitted True only when the access level is container, which lets an unauthenticated caller ENUMERATE every blob name in the container and then read each one Passthrough
requires_account_to_allow_anonymous_access True when this container's access level is blob or container, which means anonymous reads will succeed ONLY IF the parent storage account also allows anonymous access (allowBlobPublicAccess, exposed by the account module as allow_nested_items_to_be_public) Passthrough
is_static_website_content_container True when this container is the reserved $web container Passthrough
default_encryption_scope The default encryption scope reported by the service for this container Passthrough
default_encryption_scope_configured True when this module was given an explicit default_encryption_scope Derived
encryption_scope_override_enabled The provider's own attribute: true means a blob MAY be uploaded under an encryption scope other than the container's default, false means it may not Passthrough
default_encryption_scope_enforced True only when a default encryption scope was configured AND overrides are denied, so every blob in this container is guaranteed to be encrypted under that one scope Derived
encryption_scope_override_setting_ignored True when the caller set encryption_scope_override_enabled without also setting default_encryption_scope Derived
has_immutability_policy Whether an immutability policy (WORM) is configured on the container. It never says whether that policy is LOCKED β€” read the policy module's own locked output, because a locked policy makes this container and its account undeletable Passthrough
has_legal_hold Whether a legal hold is configured on the container Passthrough
metadata The user-defined name/value metadata on the container, as read back from the blob data plane Passthrough
managed_via_control_plane_only Always true for a container addressed by storage_account_id, which is the only form this module accepts Constant
refresh_reads_parent_account_properties Always true Constant
delete_removes_all_blobs Always true, and the most consequential destroy fact about this resource Constant
delete_is_not_immediately_effective Always true Constant
effective_timeouts The create/read/update/delete timeouts that will actually apply, resolving each unset field to the provider's built-in default for this resource Derived

🧠 Architecture Notes

  • Single keystone. The module owns exactly one resource, azurerm_storage_container.this, following this module suite's single-primary-resource convention. It does not create the parent account, resource group, private endpoints, or diagnostics β€” those are sibling concerns consumed by id.
  • Force-new fields destroy data. name and storage_account_id are immutable; so are default_encryption_scope and encryption_scope_override_enabled. A change to any of these replaces the container, which deletes its blobs. Treat them as create-time decisions.
  • The encryption-scope coupling. encryption_scope_override_enabled is only meaningful when default_encryption_scope is set. main.tf renders the override flag only when a scope is present, so setting it in isolation does not produce a spurious value.
  • metadata is computed. The default {} means "no user metadata"; the service may still return system metadata. Passing an explicit empty map avoids perpetual diffs.
  • No tags. This resource type does not support Azure resource tags, so the module omits the tags variable entirely β€” do not expect to tag a container.
  • id is the Resource Manager ID. In the pinned provider line the container id carries the ARM identifier, and the older resource-manager-ID attribute is deprecated; the module emits the ARM identifier through id.
  • features {} dependence. The module declares no provider block; the caller's provider "azurerm" { features {} } is required for initialization.

🧱 Design Principles

Concern Secure default (empty call) Opt-out (caller must type it)
Anonymous public access container_access_type = "private" set "blob" or "container" (and enable public blob access on the account)
Encryption at rest always on (account-level); scope-narrowing off unless a scope is supplied supply default_encryption_scope
Encryption-scope override not resolved by the empty call β€” the module leaves the flag unset, and the flag is only rendered when default_encryption_scope is set. Where no default scope is configured there is no override to permit or deny. set encryption_scope_override_enabled = false alongside a default_encryption_scope to pin every blob to that scope; true is the provider's permissive default
Credentials / subscription / region-as-auth never module inputs β€” the caller configures the provider β€”

πŸš€ Runbook

terraform init -backend=false
terraform validate
terraform fmt -check
  • Pin the module with ?ref=v1.0.0 β€” never a branch.
  • This is plan-only during authoring; a human runs terraform plan/apply from CI against real credentials.

πŸ§ͺ Testing

The offline proof gate exercises everything that does not require an Azure call:

  • terraform init -backend=false β€” resolves the pinned provider without a backend.
  • terraform validate β€” proves the configuration is type-correct against the pinned provider schema, including the container_access_type enum.
  • terraform fmt -check β€” enforces canonical formatting.

validate and fmt never contact Azure. Only terraform plan (run by a human from CI) exercises the ARM API β€” for example, confirming the referenced storage account exists and that the identity holds the required roles.

πŸ’¬ Example Output

Outputs:

id                      = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-platform-data/providers/Microsoft.Storage/storageAccounts/stplatformdata01/blobServices/default/containers/app-data"
name                    = "app-data"
has_immutability_policy = false
has_legal_hold          = false

πŸ” Troubleshooting

Symptom Cause Fix
container_access_type must be one of: private, blob, container A value outside the enum was passed. Use private, blob, or container.
Public reads still fail with blob/container access The parent account disables public blob access. Set allow_nested_items_to_be_public = true on the account, or keep the container private.
Plan shows the container being replaced A force-new field (name, storage_account_id, default_encryption_scope, encryption_scope_override_enabled) changed. Revert the change, or accept replacement knowing blobs are destroyed.
AuthorizationPermissionMismatch when reading/writing blobs The identity has a management role but no Storage Blob Data role. Assign Storage Blob Data Reader/Contributor/Owner at the account or container scope.
Deprecation warning about an account-name argument An older example set the account by name. Pass the account's Resource ID via storage_account_id.
Error: Provider configuration not present / features error The caller has no provider "azurerm" { features {} }. Add the provider block with features {} in the root module.
Encryption-scope value ignored encryption_scope_override_enabled set without default_encryption_scope. Set default_encryption_scope; the override flag only applies alongside it.

πŸ”— Related Docs

πŸ’™ "Infrastructure as Code should be standardized, consistent, and secure."

0