azurerm_management_lock导致Terraform apply执行失败的解决方法
在资源组 my-rg 中创建了azurerm_storage_account和azurerm_cosmosdb_account两类资源,同时在my-rg资源组层级配置了锁级别为 ReadOnly 的azurerm_management_lock资源,相关Terraform配置代码如下:
resource "azurerm_storage_account" "main" { name = "my-storage" resource_group_name = azurerm_resource_group.main.name ... } resource "azurerm_cosmosdb_account" "main" { name = "my-cosmosdb" resource_group_name = azurerm_resource_group.main.name ... } resource "azurerm_resource_group" "main" { name = "my-rg" ... } resource "azurerm_management_lock" "resource-group-level" { name = "terraform-managed-resources" scope = azurerm_resource_group.main.id lock_level = "ReadOnly" }
执行terraform apply命令时出现以下报错:
Error: [ERROR] Unable to List Write keys for CosmosDB Account "my-cosmosdb": documentdb.DatabaseAccountsClient#ListKeys: Failure sending request: StatusCode=409 -- Original Error: autorest/azure: Service returned an error. Status= Code="ScopeLocked" Message="The scope '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/my-rg/providers/Microsoft.DocumentDB/databaseAccounts/my-cosmosdb' cannot perform write operation because following scope(s) are locked: '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/my-rg'. Please remove the lock and try again."
Error: building Queues Client: retrieving Account Key: Listing Keys for Storage Account "my-storage" (Resource Group "my-rg"): storage.AccountsClient#ListKeys: Failure sending request: StatusCode=409 -- Original Error: autorest/azure: Service returned an error. Status= Code="ScopeLocked" Message="The scope '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/my-rg/providers/Microsoft.Storage/storageAccounts/my-storage' cannot perform write operation because following scope(s) are locked: '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/my-rg'. Please remove the lock and try again."
注:以上为简化示例,实际环境中还有大量不受该锁影响的资源,此处仅列出错误日志涉及的相关资源。
需求:在无需手动移除管理锁的前提下,需要如何配置才能正常执行terraform apply?
Azure将存储账户、CosmosDB账户的ListKeys(列出访问密钥)接口归类为写操作,资源组级别的ReadOnly锁会拦截作用域下所有写操作。Terraform创建这两类资源后,默认会调用ListKeys接口拉取密钥存入状态文件,如果锁在密钥读取操作完成前就已创建,请求会被直接拦截返回409。
根据部署阶段选择对应配置即可,全程不需要手动操作管理锁:
首次部署场景(资源和锁都未创建)
给azurerm_management_lock资源显式添加对存储账户、CosmosDB账户的依赖,调整资源创建顺序:确保存储、CosmosDB完全创建完成、密钥读取等所有初始化操作全部执行完毕后,再创建资源组级别的ReadOnly锁。配置示例:resource "azurerm_management_lock" "resource-group-level" { name = "terraform-managed-resources" scope = azurerm_resource_group.main.id lock_level = "ReadOnly" # 显式声明依赖,锁在依赖资源全部创建完成后才会部署 depends_on = [ azurerm_storage_account.main, azurerm_cosmosdb_account.main ] }锁创建完成后,后续如果没有对存储、CosmosDB资源的变更操作,Terraform不会重复调用ListKeys接口,不会触发锁拦截。
存量环境场景(锁已经存在,需要正常执行后续apply)
在azurerm provider配置块中开启锁自动托管特性,Terraform执行需要写权限的操作前会自动临时移除锁,操作完成后自动按原配置恢复,全程无人工介入:provider "azurerm" { features { management_lock { # 开启后自动临时处理操作路径上的管理锁,操作完成自动恢复 automatically_remove_on_resource_operations = true } } }额外优化配置(推荐):如果业务不需要通过账户密钥访问存储和CosmosDB,可以在对应资源块中关闭密钥认证,从根源上避免Terraform调用ListKeys接口,同时符合云资源安全最佳实践:
- 存储账户添加配置:
shared_access_key_enabled = false - CosmosDB账户添加配置:
key_based_authentication_enabled = false
- 存储账户添加配置:
内容的提问来源于stack exchange,提问作者Will

