锁定资源以保护基础结构

作为管理员,你可以锁定 Azure 订阅、资源组或资源,以防止用户意外删除和修改它们。 锁会替代任何用户权限。

可以设置锁来防止删除或修改。 在门户中,这些锁称为“删除”和“只读”。 在命令行中,这些锁称为 CanNotDelete 和 ReadOnly。

  • CanNotDelete 表示已获授权的用户可以读取和修改某个资源,但不能删除该资源。
  • ReadOnly 表示已获授权的用户可以读取某个资源,但不能删除或更新该资源。 应用此锁类似于将所有已获授权的用户限制于使用“读取者”角色提供的权限。

与基于角色的访问控制 (RBAC) 不同,可以使用管理锁来对所有用户和角色应用限制。 若要了解如何为用户和角色设置权限,请参阅 Azure RBAC

锁继承

在父范围应用锁时,该范围内所有资源都会继承相同的锁。 即使是以后添加的资源也会继承同一父锁。 继承中限制性最强的锁优先执行。

扩展资源从应用锁的资源继承锁。 例如,Microsoft.Insights/diagnosticSettings 是扩展资源类型。 如果将诊断设置应用于存储 Blob 并锁定存储帐户,则无法删除诊断设置。 此继承是合理的,因为诊断设置的完整资源 ID 为:

/subscriptions/{sub-id}/resourceGroups/{rg-name}/providers/Microsoft.Storage/storageAccounts/{storage-name}/blobServices/default/providers/microsoft.insights/diagnosticSettings/{setting-name}"

这与锁定资源的资源 ID 的范围匹配:

/subscriptions/{sub-id}/resourceGroups/{rg-name}/providers/Microsoft.Storage/storageAccounts/{storage-name}

如果你对某个资源拥有“删除”锁并尝试删除其资源组,该功能会阻止整个删除操作。 即使资源组或资源组中的其他资源已解锁,也不会发生删除操作。 绝不会出现部分删除。

取消 Azure 订阅时:

  • 资源锁不会阻止取消该订阅。
  • Azure 通过停用资源而不是立即删除它们来保留资源。
  • Azure 只会在等待期过后才永久删除资源。

了解锁的作用域

注意

锁仅适用于控制平面 Azure 操作,而不适用于数据平面操作。

Azure 控制平面操作转到 https://management.chinacloudapi.cn。 Azure 数据平面操作转到服务实例,例如 https://myaccount.blob.core.chinacloudapi.cn/。 请参阅 Azure 控制平面和数据平面。 要了解哪些操作使用控制平面 URL,请参阅 Azure REST API

这种差别意味着,锁可以防止资源遭到更改,但不限制资源执行其功能的方式。 例如,在 SQL 数据库逻辑服务器上的 ReadOnly 锁可以防止该服务器被删除或修改。 它允许在服务器数据库中创建、更新或删除数据。 数据平面操作允许数据事务。 这些请求不会转到 https://management.chinacloudapi.cn

应用锁之前的注意事项

应用锁可能会导致意外结果。 某些看似不会修改资源的操作需要执行阻止的操作。 锁可以防止 POST 方法将数据发送到 Azure 资源管理器 (ARM) API。 阻止的操作的一些常见示例包括:

  • 存储帐户上的只读锁阻止用户列出帐户密钥。 POST 请求处理 Azure 存储列出密钥操作,以保护对帐户密钥的访问。 帐户密钥提供对存储帐户中数据的完整访问权限。 如果为存储帐户配置了只读锁,则没有帐户密钥的用户需要使用 Microsoft Entra 凭据才能访问 blob 或队列数据。 只读锁还阻止分配存储帐户或数据容器(blob 容器或队列)范围内的 Azure RBAC 角色。

  • 存储帐户上的只读锁可以防止范围限定为存储帐户或数据容器(blob 容器或队列)的 RBAC 分配。

  • 存储帐户上的只读锁会阻止创建 Blob 容器。

  • 存储帐户上的只读锁会阻止创建 Blob 容器。 但是,可以通过控制平面和数据平面在存储帐户上创建操作。 只读锁仅阻止控制平面创建请求,但用户仍可以通过数据平面对资源执行有效的创建操作。

  • 存储帐户上的 read-only 锁或 cannot-delete 锁无法防止删除或修改其数据。 它也不能保护 Blob、队列、表或文件中的数据。

  • 存储帐户 API 会公开数据平面控制平面操作。 如果请求使用数据平面操作,那么存储帐户上的锁不会保护该存储帐户中的 Blob、队列、表或文件数据。 但是,如果请求使用控制平面操作,那么锁会保护这些资源。

    例如,如果请求使用“文件共享 - 删除”(控制平面操作),删除将会失败。 如果请求使用“删除共享”(数据平面操作),删除将成功。 我们建议使用控制平面操作。

  • 网络安全组 (NSG) 上的只读锁会阻止创建相应的 NSG 流日志。 网络安全组 (NSG) 上的无法删除锁不会阻止创建或修改相应的 NSG 流日志。

  • 应用服务资源上的只读锁将阻止 Visual Studio 服务器资源管理器显示资源的文件,因为该交互需要写入访问权限。

  • 包含应用服务计划的资源组上的 read-only 锁会阻止你纵向或横向扩展计划

  • 包含虚拟机的资源组上的 read-only 锁将阻止所有用户启动或重启该虚拟机。 这些操作需要 POST 方法请求。

  • 资源组上的只读锁可防止将现有资源移入或移出资源组。 但请注意,具有只读锁的资源可以移动到另一个资源组。

  • 包含自动化帐户的资源组上的只读锁会阻止所有 Runbook 启动。 这些操作需要 POST 方法请求。

  • 资源或资源组上的“无法删除”锁会阻止删除 Azure RBAC 分配。

  • 资源组上的不可删除锁可防止 Azure 资源管理器自动删除历史记录中的部署。 如果历史记录中达到 800 个部署,则部署会失败。

  • Azure 备份服务创建的资源组上的“不能删除”锁会导致备份失败。 该服务最多支持 18 个还原点。 锁定后,备份服务无法清理还原点。 有关详细信息,请参阅常见问题解答 - 备份 Azure VM

  • 包含 Azure 机器学习工作区的资源组上的“无法删除”锁会阻止 Azure 机器学习计算群集的自动缩放功能正常工作。 使用该锁,自动缩放功能将无法删除未使用的节点。 解决方案使用的资源多于工作负载所需的资源。

  • Log Analytics 工作区上的只读锁会阻止启用“用户和实体行为分析(UEBA)”。

  • Log Analytics 工作区上的“不可删除”锁不会阻止数据清除操作 而是会从用户中删除数据清除角色。

  • 订阅上的只读锁会导致 Azure 顾问无法正常运行。 顾问将无法存储其查询的结果。

  • 应用程序网关上的只读锁将阻止获取应用程序网关的后端运行状况。 该操作使用 POST 方法 - 一个 read-only 锁阻止方法。

  • Azure Kubernetes 服务 (AKS) 群集上的只读锁可以限制如何通过门户访问群集资源。 只读锁可以防止使用 Azure 门户中的 AKS 群集 Kubernetes 资源部分来选择群集资源。 这些操作需要通过 POST 方法请求进行身份验证。

  • 在删除保护或禁用复制时,受 Site Recovery 保护的虚拟机上的“不可删除”锁可防止完全删除与 Site Recovery 相关的某些资源链接。 如果计划稍后再次保护 VM,则需要在禁用保护之前删除该锁。 如果没有删除该锁,则需要执行某些步骤来清理过时的链接,然后才能保护 VM。 有关详细信息,请参阅对 Azure VM 复制进行故障排除

  • 对于 Postgresql,虚拟网络不应在虚拟网络或子网级别设置任何资源锁,因为锁可能会干扰网络和 DNS 上的操作。 在虚拟网络中创建服务器之前,请确保从虚拟网络和所有子网中移除任何删除或只读锁。 创建服务器后,可以重新应用锁。

谁可以创建或删除锁

若要创建或删除管理锁,你需要有权访问 Microsoft.Authorization/*Microsoft.Authorization/locks/* 操作。 分配给“所有者”和“用户访问管理员”角色的用户具有所需的访问权限。 某些专用内置角色也授予此访问权限。 可以创建拥有所需权限的自定义角色。

托管应用程序和锁

某些 Azure 服务(如 Azure Databricks)使用托管应用程序来实现该服务。 在这种情况下,该服务将创建两个资源组。 其中一个资源组是包含服务概述的已解锁资源组。 另一个是包含服务基础结构的已锁定资源组。

如果尝试删除基础结构资源组,将会收到一条错误消息,指出资源组已锁定。 如果你尝试删除基础结构资源组的锁,将会收到一条错误消息,指出无法删除该锁,因为它由系统应用程序拥有。

应该删除服务,这样也会删除基础结构资源组。

对于托管应用程序,请选择你部署的服务。

Azure 门户的屏幕截图,显示所选的 Azure Databricks 实例。

请注意,服务包含托管资源组的链接。 该资源组包含基础结构且已锁定。 只能间接删除它。

显示 Azure 门户中的受管理资源组链接的屏幕截图。

若要删除服务的所有内容(包括锁定的基础结构资源组),请选择该服务对应的“删除”。

Azure 门户的屏幕截图,其中显示了所选服务的“删除”选项。

配置锁定

门户

在左侧导航面板中,订阅锁定功能的名称为“资源锁”,而资源组锁定功能的名称为“锁”。

  1. 在要锁定的资源、资源组或订阅的“设置”边栏选项卡中,选择“锁定”

    选择锁。

  2. 要添加锁,请选择“添加”。 如果要在父级别创建锁,请选择父级。 当前选定的资源将从父级继承锁。 例如,可以锁定资源组,以便向其所有资源应用锁。

    添加锁。

  3. 为该锁提供名称和锁级别。 (可选)可以添加注释来描述该锁。

    设置锁。

  4. 要删除锁,请选择“删除”按钮。

    删除锁。

模板

使用 ARM 模板或 Bicep 文件部署锁时,最好了解部署范围和锁范围的协同工作方式。 若要在部署范围应用锁(例如锁定资源组或订阅),请将 scope 属性保持未设置状态。 锁定部署范围内的资源时,请在锁中设置 scope 属性。

以下模板会将锁应用于资源组。 请注意,锁资源没有 scope 属性,因为锁范围与部署范围匹配。 在资源组级别部署此模板。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
  },
  "resources": [
    {
      "type": "Microsoft.Authorization/locks",
      "apiVersion": "2016-09-01",
      "name": "rgLock",
      "properties": {
        "level": "CanNotDelete",
        "notes": "Resource group should not be deleted."
      }
    }
  ]
}

若要创建资源组并对其进行锁定,请在订阅级别部署以下模板。

{
  "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "rgName": {
      "type": "string"
    },
    "rgLocation": {
      "type": "string"
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Resources/resourceGroups",
      "apiVersion": "2021-04-01",
      "name": "[parameters('rgName')]",
      "location": "[parameters('rgLocation')]",
      "properties": {}
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "lockDeployment",
      "resourceGroup": "[parameters('rgName')]",
      "dependsOn": [
        "[resourceId('Microsoft.Resources/resourceGroups/', parameters('rgName'))]"
      ],
      "properties": {
        "mode": "Incremental",
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {},
          "variables": {},
          "resources": [
            {
              "type": "Microsoft.Authorization/locks",
              "apiVersion": "2016-09-01",
              "name": "rgLock",
              "properties": {
                "level": "CanNotDelete",
                "notes": "Resource group and its resources should not be deleted."
              }
            }
          ],
          "outputs": {}
        }
      }
    }
  ],
  "outputs": {}
}

对资源组中的资源应用锁时,请添加 scope 属性。 将 scope 设置为要锁定的资源的名称。

以下示例演示可创建应用服务计划、网站和网站上的锁的模板。 锁的范围设置为网站。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "hostingPlanName": {
      "type": "string"
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    }
  },
  "variables": {
    "siteName": "[concat('ExampleSite', uniqueString(resourceGroup().id))]"
  },
  "resources": [
    {
      "type": "Microsoft.Web/serverfarms",
      "apiVersion": "2020-12-01",
      "name": "[parameters('hostingPlanName')]",
      "location": "[parameters('location')]",
      "sku": {
        "tier": "Free",
        "name": "f1",
        "capacity": 0
      },
      "properties": {
        "targetWorkerCount": 1
      }
    },
    {
      "type": "Microsoft.Web/sites",
      "apiVersion": "2020-12-01",
      "name": "[variables('siteName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]"
      ],
      "properties": {
        "serverFarmId": "[parameters('hostingPlanName')]"
      }
    },
    {
      "type": "Microsoft.Authorization/locks",
      "apiVersion": "2016-09-01",
      "name": "siteLock",
      "scope": "[concat('Microsoft.Web/sites/', variables('siteName'))]",
      "dependsOn": [
        "[resourceId('Microsoft.Web/sites', variables('siteName'))]"
      ],
      "properties": {
        "level": "CanNotDelete",
        "notes": "Site should not be deleted."
      }
    }
  ]
}

Azure PowerShell

可以通过 Azure PowerShell 使用 New-AzResourceLock 命令锁定已部署的资源。

若要锁定某个资源,请提供该资源的名称、其资源类型及其资源组名称。

New-AzResourceLock -LockLevel CanNotDelete -LockName LockSite -ResourceName examplesite -ResourceType Microsoft.Web/sites -ResourceGroupName exampleresourcegroup

若要锁定某个资源组,请提供该资源组的名称。

New-AzResourceLock -LockName LockGroup -LockLevel CanNotDelete -ResourceGroupName exampleresourcegroup

若要获取有关某个锁的信息,请使用 Get-AzResourceLock。 若要获取订阅中的所有锁,请使用:

Get-AzResourceLock

若要获取某个资源的所有锁,请使用:

Get-AzResourceLock -ResourceName examplesite -ResourceType Microsoft.Web/sites -ResourceGroupName exampleresourcegroup

若要获取某个资源组的所有锁,请使用:

Get-AzResourceLock -ResourceGroupName exampleresourcegroup

若要删除某个资源的锁,请使用:

$lockId = (Get-AzResourceLock -ResourceGroupName exampleresourcegroup -ResourceName examplesite -ResourceType Microsoft.Web/sites).LockId
Remove-AzResourceLock -LockId $lockId

若要删除某个资源组的锁,请使用:

$lockId = (Get-AzResourceLock -ResourceGroupName exampleresourcegroup).LockId
Remove-AzResourceLock -LockId $lockId

Azure CLI

可以通过 Azure CLI 使用 az lock create 命令锁定已部署的资源。

若要锁定某个资源,请提供该资源的名称、其资源类型及其资源组名称。

az lock create --name LockSite --lock-type CanNotDelete --resource-group exampleresourcegroup --resource-name examplesite --resource-type Microsoft.Web/sites

若要锁定某个资源组,请提供该资源组的名称。

az lock create --name LockGroup --lock-type CanNotDelete --resource-group exampleresourcegroup

若要获取有关某个锁的信息,请使用 az lock list。 若要获取订阅中的所有锁,请使用:

az lock list

若要获取某个资源的所有锁,请使用:

az lock list --resource-group exampleresourcegroup --resource-name examplesite --namespace Microsoft.Web --resource-type sites --parent ""

若要获取某个资源组的所有锁,请使用:

az lock list --resource-group exampleresourcegroup

若要删除某个资源的锁,请使用:

lockid=$(az lock show --name LockSite --resource-group exampleresourcegroup --resource-type Microsoft.Web/sites --resource-name examplesite --output tsv --query id)
az lock delete --ids $lockid

若要删除某个资源组的锁,请使用:

lockid=$(az lock show --name LockSite --resource-group exampleresourcegroup  --output tsv --query id)
az lock delete --ids $lockid

Python

可以使用 ManagementLockClient.management_locks.create_or_update_at_resource_group_level 命令锁定部署的资源。

若要锁定某个资源,请提供该资源的名称、其资源类型及其资源组名称。

import os
from azure.identity import AzureCliCredential
from azure.mgmt.resource import ManagementLockClient

credential = AzureCliCredential()
subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"]

lock_client = ManagementLockClient(credential, subscription_id)

lock_result = lock_client.management_locks.create_or_update_at_resource_level(
    "exampleGroup",
    "Microsoft.Web",
    "",
    "sites",
    "examplesite",
    "lockSite",
    {
        "level": "CanNotDelete"
    }
)

若要锁定某个资源组,请提供该资源组的名称。

import os
from azure.identity import AzureCliCredential
from azure.mgmt.resource import ManagementLockClient

credential = AzureCliCredential()
subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"]

lock_client = ManagementLockClient(credential, subscription_id)

lock_result = lock_client.management_locks.create_or_update_at_resource_group_level(
    "exampleGroup",
    "lockGroup",
    {
        "level": "CanNotDelete"
    }
)

若要获取有关订阅中所有锁的信息,请使用 ManagementLockClient.management_locks.get。 若要获取订阅中的所有锁,请使用:

import os
from azure.identity import AzureCliCredential
from azure.mgmt.resource import ManagementLockClient

credential = AzureCliCredential()
subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"]

lock_client = ManagementLockClient(credential, subscription_id)

lock_result = lock_client.management_locks.list_at_subscription_level()

for lock in lock_result:
    print(f"Lock name: {lock.name}")
    print(f"Lock level: {lock.level}")
    print(f"Lock notes: {lock.notes}")

若要获取某个资源的锁,请使用:

import os
from azure.identity import AzureCliCredential
from azure.mgmt.resource import ManagementLockClient

credential = AzureCliCredential()
subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"]

lock_client = ManagementLockClient(credential, subscription_id)

lock_result = lock_client.management_locks.get_at_resource_level(
    "exampleGroup",
    "Microsoft.Web",
    "",
    "sites",
    "examplesite",
    "lockSite"
)

print(f"Lock ID: {lock_result.id}")
print(f"Lock Name: {lock_result.name}")
print(f"Lock Level: {lock_result.level}")

若要获取某个资源组的锁,请使用:

import os
from azure.identity import AzureCliCredential
from azure.mgmt.resource import ManagementLockClient

credential = AzureCliCredential()
subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"]

lock_client = ManagementLockClient(credential, subscription_id)

lock_result = lock_client.management_locks.get_at_resource_group_level(
    "exampleGroup",
    "lockGroup"
)

print(f"Lock ID: {lock_result.id}")
print(f"Lock Level: {lock_result.level}")

若要删除某个资源的锁,请使用:

import os
from azure.identity import AzureCliCredential
from azure.mgmt.resource import ManagementLockClient

credential = AzureCliCredential()
subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"]

lock_client = ManagementLockClient(credential, subscription_id)

lock_client.management_locks.delete_at_resource_level(
    "exampleGroup",
    "Microsoft.Web",
    "",
    "sites",
    "examplesite",
    "lockSite"
)

若要删除某个资源组的锁,请使用:

import os
from azure.identity import AzureCliCredential
from azure.mgmt.resource import ManagementLockClient

credential = AzureCliCredential()
subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"]

lock_client = ManagementLockClient(credential, subscription_id)

lock_client.management_locks.delete_at_resource_group_level("exampleGroup", "lockGroup")

REST API

可以使用 管理锁的 REST API锁定已部署的资源。 可以使用 REST API 创建和删除锁,以及检索有关现有锁的信息。

若要创建一个锁,请运行:

PUT https://management.chinacloudapi.cn/{scope}/providers/Microsoft.Authorization/locks/{lock-name}?api-version={api-version}

作用域可能是订阅、资源组或资源。 锁名称可以是想要使用的任意名称。 对于 API 版本,请使用 2016-09-01。

在请求中,请包含用于指定锁属性的 JSON 对象。

{
  "properties": {
  "level": "CanNotDelete",
  "notes": "Optional text notes."
  }
}

后续步骤