Azure 密钥保管库 是一项云服务,它为机密(例如密钥、密码和证书)提供安全存储。 本快速入门重点介绍部署Azure 资源管理器模板(ARM 模板)以创建密钥保管库和自签名证书的过程。
Azure 资源管理器模板是一个 JavaScript 对象表示法(JSON)文件,用于定义项目的基础结构和配置。 模板使用声明性语法。 你可以在不编写用于创建部署的编程命令序列的情况下,描述预期部署。
如果你的环境满足先决条件,并且你熟悉如何使用 ARM 模板,请选择“部署到 Azure”按钮。 模板将在Azure门户中打开。
Prerequisites
若要完成本文,需要做好以下准备:
- 如果没有 Azure 订阅,请在开始之前先创建一个免费帐户。
查看模板
本快速入门中使用的模板来自 Azure 快速入门模板。
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.42.1.51946",
"templateHash": "11850030662128066774"
}
},
"parameters": {
"vaultName": {
"type": "string",
"metadata": {
"description": "The name of the key vault to be created."
}
},
"certificateName": {
"type": "string",
"metadata": {
"description": "The name of the certificate to be created."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "The location of the resources."
}
},
"skuName": {
"type": "string",
"defaultValue": "standard",
"allowedValues": [
"standard",
"premium"
],
"metadata": {
"description": "The SKU of the vault to be created."
}
},
"certificateCommonName": {
"type": "string",
"defaultValue": "[parameters('certificateName')]",
"metadata": {
"description": "The common name (subject) for the self-signed certificate. Defaults to the certificate name."
}
},
"validityInMonths": {
"type": "int",
"defaultValue": 12,
"minValue": 1,
"maxValue": 1200,
"metadata": {
"description": "The validity of the certificate in months."
}
}
},
"resources": [
{
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2023-07-01",
"name": "[parameters('vaultName')]",
"location": "[parameters('location')]",
"properties": {
"enableRbacAuthorization": true,
"enableSoftDelete": true,
"softDeleteRetentionInDays": 90,
"enablePurgeProtection": true,
"enabledForDeployment": false,
"enabledForDiskEncryption": false,
"enabledForTemplateDeployment": false,
"tenantId": "[subscription().tenantId]",
"sku": {
"name": "[parameters('skuName')]",
"family": "A"
},
"networkAcls": {
"defaultAction": "Allow",
"bypass": "AzureServices"
}
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2025-04-01",
"name": "[format('create-{0}', parameters('certificateName'))]",
"properties": {
"expressionEvaluationOptions": {
"scope": "inner"
},
"mode": "Incremental",
"parameters": {
"akvName": {
"value": "[parameters('vaultName')]"
},
"location": {
"value": "[parameters('location')]"
},
"certificateNames": {
"value": [
"[parameters('certificateName')]"
]
},
"certificateCommonNames": {
"value": [
"[parameters('certificateCommonName')]"
]
},
"validity": {
"value": "[parameters('validityInMonths')]"
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.19.5.34762",
"templateHash": "3959456113273968386"
},
"name": "Key Vault Certificate Creation",
"description": "Create Key Vault self-signed certificates. Requires Key Vaults to be using RBAC Authorization, not Access Policies.",
"owner": "Aks-Bicep-Accelerator-Maintainers"
},
"parameters": {
"akvName": {
"type": "string",
"metadata": {
"description": "The name of the Azure Key Vault"
}
},
"location": {
"type": "string",
"metadata": {
"description": "The location to deploy the resources to"
}
},
"forceUpdateTag": {
"type": "string",
"defaultValue": "[utcNow()]",
"metadata": {
"description": "How the deployment script should be forced to execute"
}
},
"rbacRolesNeededOnKV": {
"type": "string",
"defaultValue": "a4417e6f-fecd-4de8-b567-7b0420556985",
"metadata": {
"description": "The RoleDefinitionId required for the DeploymentScript resource to interact with KeyVault"
}
},
"useExistingManagedIdentity": {
"type": "bool",
"defaultValue": false,
"metadata": {
"description": "Does the Managed Identity already exists, or should be created"
}
},
"managedIdentityName": {
"type": "string",
"defaultValue": "[format('id-KeyVaultCertificateCreator-{0}', parameters('location'))]",
"metadata": {
"description": "Name of the Managed Identity resource"
}
},
"existingManagedIdentitySubId": {
"type": "string",
"defaultValue": "[subscription().subscriptionId]",
"metadata": {
"description": "For an existing Managed Identity, the Subscription Id it is located in"
}
},
"existingManagedIdentityResourceGroupName": {
"type": "string",
"defaultValue": "[resourceGroup().name]",
"metadata": {
"description": "For an existing Managed Identity, the Resource Group it is located in"
}
},
"certificateNames": {
"type": "array",
"metadata": {
"description": "The names of the certificate to create. Use when creating many certificates."
}
},
"certificateCommonNames": {
"type": "array",
"defaultValue": "[parameters('certificateNames')]",
"metadata": {
"description": "The common names of the certificate to create. Use when creating many certificates."
}
},
"initialScriptDelay": {
"type": "string",
"defaultValue": "0",
"metadata": {
"description": "A delay before the script import operation starts. Primarily to allow Azure AAD Role Assignments to propagate"
}
},
"cleanupPreference": {
"type": "string",
"defaultValue": "OnSuccess",
"metadata": {
"description": "When the script resource is cleaned up"
},
"allowedValues": [
"OnSuccess",
"OnExpiration",
"Always"
]
},
"issuerName": {
"type": "string",
"defaultValue": "Self",
"metadata": {
"description": "Self, or user defined {IssuerName} for certificate signing"
}
},
"issuerProvider": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Certificate Issuer Provider, DigiCert, GlobalSign, or internal options may be used."
}
},
"disabled": {
"type": "bool",
"defaultValue": false,
"metadata": {
"description": "Create certificate in disabled state. Default: false"
}
},
"accountId": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Account ID of Certificate Issuer Account"
}
},
"issuerPassword": {
"type": "securestring",
"defaultValue": "",
"metadata": {
"description": "Password of Certificate Issuer Account"
}
},
"organizationId": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Organization ID of Certificate Issuer Account"
}
},
"isCrossTenant": {
"type": "bool",
"defaultValue": false,
"metadata": {
"description": "Override this parameter if using this in cross tenant scenarios"
}
},
"reuseKey": {
"type": "bool",
"defaultValue": true,
"metadata": {
"description": "The default policy might cause errors about CSR being used before, so set this to false if that happens"
}
},
"validity": {
"type": "int",
"defaultValue": 12,
"metadata": {
"description": "Optional. Override default validityInMonths 12 value"
},
"maxValue": 1200,
"minValue": 1
},
"performRoleAssignment": {
"type": "bool",
"defaultValue": true,
"metadata": {
"description": "Set to false to disable role assignments within this module. Default: true"
}
}
},
"variables": {
"$fxv#0": "#!/bin/bash\nset -e\ninitialDelay=\"${initialDelay:-5}\"\nretryMax=\"${retryMax:-5}\"\ncertName=\"${certName:-default-cert}\"\ncertCommonName=\"${certCommonName:-default}\"\nvalidity=\"${validity:-12}\"\nakvName=\"${akvName:-keyvault}\"\nissuerName=\"${issuerName:-}\"\nreuseKey=\"${reuseKey:-true}\"\nretrySleep=\"${retrySleep:-5}\"\n\necho \"Waiting on Identity RBAC replication (\\\"$initialDelay\\\")\"\nsleep \"$initialDelay\"\n\n#Retry loop to catch errors (usually RBAC delays)\nretryLoopCount=0\nuntil [ \"$retryLoopCount\" -ge \"$retryMax\" ]\ndo\n echo \"Creating AKV Cert $certName with CN $certCommonName (attempt $retryLoopCount)...\"\n\n if [ -z \"$issuerName\" ] || [ -z \"$issuerProvider\" ]; then\n policy=$(az keyvault certificate get-default-policy \\\n | sed -e s/\\\"validityInMonths\\\":\\ 12/\\\"validityInMonths\\\":\\ \"${validity}\"/g \\\n | sed -e s/CN=CLIGetDefaultPolicy/CN=\"${certCommonName}\"/g )\n else\n if [ \"$issuerProvider\" == \"DigiCert\" ] || [ \"$issuerProvider\" == \"GlobalCert\" ]; then\n az keyvault certificate issuer create \\\n --vault-name \"$akvName\" \\\n --issuer-name \"$issuerName\" \\\n --provider-name \"$issuerProvider\" \\\n --account-id \"$accountId\" \\\n --password \"$issuerPassword\" \\\n --organizatiion-id \"$organizationId\"\n else\n az keyvault certificate issuer create \\\n --vault-name \"$akvName\" \\\n --issuer-name \"$issuerName\" \\\n --provider-name \"$issuerProvider\"\n fi\n policy=$(az keyvault certificate get-default-policy \\\n | sed -e s/\\\"validityInMonths\\\":\\ 12/\\\"validityInMonths\\\":\\ \"${validity}\"/g \\\n | sed -e s/CN=CLIGetDefaultPolicy/CN=\"${certCommonName}\"/g \\\n | sed -e s/\\\"name\\\":\\ \\\"Self\\\"/\\\"name\\\":\\ \\\"\"${issuerName}\"\\\"/g \\\n | sed -e s/\\\"reuseKey\\\":\\ true/\\\"reuseKey\\\":\\ \"${reuseKey}\"/g )\n fi\n az keyvault certificate create \\\n --vault-name \"$akvName\" \\\n -n \"$certName\" \\\n -p \"$policy\" \\\n --disabled \"$disabled\" \\\n && break\n\n sleep \"$retrySleep\"\n retryLoopCount=$((retryLoopCount+1))\ndone\n\necho \"Getting Certificate $certName\";\nretryLoopCount=0\ncreatedCert=$(az keyvault certificate show -n \"$certName\" --vault-name \"$akvName\" -o json)\nwhile [ -z \"$(echo \"$createdCert\" | jq -r '.x509ThumbprintHex')\" ] && [ $retryLoopCount -lt \"$retryMax\" ]\ndo\n echo \"Waiting for cert creation (attempt $retryLoopCount)...\"\n sleep $retrySleep\n createdCert=$(az keyvault certificate show -n $certName --vault-name $akvName -o json)\n retryLoopCount=$((retryLoopCount+1))\ndone\n\nunversionedSecretId=$(echo $createdCert | jq -r \".sid\" | cut -d'/' -f-5) # remove the version from the url;\njsonOutputString=$(echo $createdCert | jq --arg usid $unversionedSecretId '{name: .name ,certSecretId: {versioned: .sid, unversioned: $usid }, thumbprint: .x509Thumbprint, thumbprintHex: .x509ThumbprintHex}')\necho $jsonOutputString > $AZ_SCRIPTS_OUTPUT_PATH\n",
"delegatedManagedIdentityResourceId": "[if(parameters('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')))]"
},
"resources": [
{
"condition": "[not(parameters('useExistingManagedIdentity'))]",
"type": "Microsoft.ManagedIdentity/userAssignedIdentities",
"apiVersion": "2018-11-30",
"name": "[parameters('managedIdentityName')]",
"location": "[parameters('location')]",
"metadata": {
"description": "A new managed identity that will be created in this Resource Group, this is the default option"
}
},
{
"condition": "[parameters('performRoleAssignment')]",
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2022-04-01",
"scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('akvName'))]",
"name": "[guid(resourceId('Microsoft.KeyVault/vaults', parameters('akvName')), parameters('rbacRolesNeededOnKV'), parameters('managedIdentityName'), string(parameters('useExistingManagedIdentity')))]",
"properties": {
"roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', parameters('rbacRolesNeededOnKV'))]",
"principalId": "[if(parameters('useExistingManagedIdentity'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2018-11-30').principalId, reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2018-11-30').principalId)]",
"principalType": "ServicePrincipal",
"delegatedManagedIdentityResourceId": "[if(parameters('isCrossTenant'), variables('delegatedManagedIdentityResourceId'), null())]"
},
"dependsOn": [
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]"
]
},
{
"copy": {
"name": "createImportCerts",
"count": "[length(parameters('certificateNames'))]"
},
"type": "Microsoft.Resources/deploymentScripts",
"apiVersion": "2020-10-01",
"name": "[format('AKV-Cert-{0}-{1}', parameters('akvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))]",
"location": "[parameters('location')]",
"identity": {
"type": "UserAssigned",
"userAssignedIdentities": {
"[format('{0}', if(parameters('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))))]": {}
}
},
"kind": "AzureCLI",
"properties": {
"forceUpdateTag": "[parameters('forceUpdateTag')]",
"azCliVersion": "2.35.0",
"timeout": "PT10M",
"retentionInterval": "P1D",
"environmentVariables": [
{
"name": "akvName",
"value": "[parameters('akvName')]"
},
{
"name": "certName",
"value": "[parameters('certificateNames')[copyIndex()]]"
},
{
"name": "certCommonName",
"value": "[parameters('certificateCommonNames')[copyIndex()]]"
},
{
"name": "initialDelay",
"value": "[parameters('initialScriptDelay')]"
},
{
"name": "issuerName",
"value": "[parameters('issuerName')]"
},
{
"name": "issuerProvider",
"value": "[parameters('issuerProvider')]"
},
{
"name": "disabled",
"value": "[toLower(string(parameters('disabled')))]"
},
{
"name": "retryMax",
"value": "10"
},
{
"name": "retrySleep",
"value": "5s"
},
{
"name": "accountId",
"value": "[parameters('accountId')]"
},
{
"name": "issuerPassword",
"secureValue": "[parameters('issuerPassword')]"
},
{
"name": "organizationId",
"value": "[parameters('organizationId')]"
},
{
"name": "reuseKey",
"value": "[toLower(string(parameters('reuseKey')))]"
},
{
"name": "validity",
"value": "[string(parameters('validity'))]"
}
],
"scriptContent": "[variables('$fxv#0')]",
"cleanupPreference": "[parameters('cleanupPreference')]"
},
"dependsOn": [
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]",
"[extensionResourceId(resourceId('Microsoft.KeyVault/vaults', parameters('akvName')), 'Microsoft.Authorization/roleAssignments', guid(resourceId('Microsoft.KeyVault/vaults', parameters('akvName')), parameters('rbacRolesNeededOnKV'), parameters('managedIdentityName'), string(parameters('useExistingManagedIdentity'))))]"
]
}
],
"outputs": {
"certificateNames": {
"type": "array",
"metadata": {
"description": "Certificate names"
},
"copy": {
"count": "[length(parameters('certificateNames'))]",
"input": "[createArray(reference(resourceId('Microsoft.Resources/deploymentScripts', format('AKV-Cert-{0}-{1}', parameters('akvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))), '2020-10-01').outputs.name)]"
}
},
"certificateSecretIds": {
"type": "array",
"metadata": {
"description": "KeyVault secret ids to the created version"
},
"copy": {
"count": "[length(parameters('certificateNames'))]",
"input": "[createArray(reference(resourceId('Microsoft.Resources/deploymentScripts', format('AKV-Cert-{0}-{1}', parameters('akvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))), '2020-10-01').outputs.certSecretId.versioned)]"
}
},
"certificateSecretIdUnversioneds": {
"type": "array",
"metadata": {
"description": "KeyVault secret ids which uses the unversioned uri"
},
"copy": {
"count": "[length(parameters('certificateNames'))]",
"input": "[createArray(reference(resourceId('Microsoft.Resources/deploymentScripts', format('AKV-Cert-{0}-{1}', parameters('akvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))), '2020-10-01').outputs.certSecretId.unversioned)]"
}
},
"certificateThumbpints": {
"type": "array",
"metadata": {
"description": "Certificate Thumbprints"
},
"copy": {
"count": "[length(parameters('certificateNames'))]",
"input": "[createArray(reference(resourceId('Microsoft.Resources/deploymentScripts', format('AKV-Cert-{0}-{1}', parameters('akvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))), '2020-10-01').outputs.thumbprint)]"
}
},
"certificateThumbprintHexs": {
"type": "array",
"metadata": {
"description": "Certificate Thumbprints (in hex)"
},
"copy": {
"count": "[length(parameters('certificateNames'))]",
"input": "[createArray(reference(resourceId('Microsoft.Resources/deploymentScripts', format('AKV-Cert-{0}-{1}', parameters('akvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))), '2020-10-01').outputs.thumbprintHex)]"
}
}
}
}
},
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', parameters('vaultName'))]"
]
}
],
"outputs": {
"location": {
"type": "string",
"value": "[parameters('location')]"
},
"name": {
"type": "string",
"value": "[parameters('vaultName')]"
},
"resourceGroupName": {
"type": "string",
"value": "[resourceGroup().name]"
},
"resourceId": {
"type": "string",
"value": "[resourceId('Microsoft.KeyVault/vaults', parameters('vaultName'))]"
},
"certificateSecretId": {
"type": "string",
"value": "[reference(resourceId('Microsoft.Resources/deployments', format('create-{0}', parameters('certificateName'))), '2025-04-01').outputs.certificateSecretIds.value[0][0]]"
},
"certificateThumbprint": {
"type": "string",
"value": "[reference(resourceId('Microsoft.Resources/deployments', format('create-{0}', parameters('certificateName'))), '2025-04-01').outputs.certificateThumbprintHexs.value[0][0]]"
}
}
}
该模板中定义了两个 Azure 资源:
- Microsoft.KeyVault/vaults:创建 Azure 密钥保管库。
- Microsoft。resources/deployments:运行部署脚本(create-kv-certificate)的嵌套部署,以在保管库中创建自签名证书。 证书是数据平面资源,不能直接使用 ARM 资源类型创建。
该模板创建启用了 Azure RBAC 授权的密钥保管库。 这意味着保管库使用Azure基于角色的访问控制(Azure RBAC)进行数据平面授权,而不是访问策略。 该证书将创建为具有指定主题名称的自签名证书。
可以在 Azure 快速入门模板中找到更多 Azure 密钥保管库 模板示例。
部署模板
选择下图以登录到Azure并打开模板。 该模板创建密钥保管库和证书。
选择或输入以下值。 除非指定了默认值,否则请使用默认值。
- Subscription:选择Azure订阅。
- 资源组:选择“新建”,为资源组输入一个独一无二的名称,然后选择“确定”。
- 区域:选择一个位置。 例如,中国北部。
-
保管库名称:输入密钥保管库的名称,该名称在命名空间中
vault.azure.cn必须全局唯一。 - 证书名称:输入证书的名称。 例如 ,myCert。
- Sku 名称:选择 标准 或 高级。 默认值为 标准。
- 证书公用名:可选。 证书主题的公用名(例如,CN=contoso.com)。 默认为证书名称。
- 有效期(以月为单位):证书有效期(以月为单位)。 默认值为 12。
选择查看 + 创建,然后选择创建。 成功部署密钥保管库和证书后,会收到通知。
还可以使用Azure PowerShell、Azure CLI或 REST API 部署模板。 若要了解其他部署方法,请参阅部署模板。
分配 密钥保管库 RBAC 角色
此模板创建的密钥保管库使用 Azure RBAC 进行授权。 若要通过数据平面访问证书(例如,使用Azure CLI或Azure PowerShell),需要为自己分配适当的角色。
获取 Microsoft Entra 用户对象 ID:
az ad signed-in-user show --query id -o tsv在密钥保管库上,将 密钥保管库 证书主管 角色分配给自己:
echo "Enter your key vault name:" && read keyVaultName && az role assignment create --role "Key Vault Certificates Officer" \ --assignee-object-id $(az ad signed-in-user show --query id -o tsv) \ --scope $(az keyvault show --name $keyVaultName --query id -o tsv)注释
角色分配可能需要一两分钟才能生效。
查看已部署的资源
可以使用Azure门户检查密钥保管库和证书,也可以使用以下Azure CLI或Azure PowerShell脚本列出创建的证书。
echo "Enter your key vault name:" &&
read keyVaultName &&
az keyvault certificate list --vault-name $keyVaultName &&
echo "Press [ENTER] to continue ..."
清理资源
其他 密钥保管库 快速入门与教程,都是以此快速入门为基础开发的。 如果打算继续使用后续的快速入门和教程,则可能需要保留这些资源。 如果不再需要资源组,可以将其删除,这将删除 密钥保管库 和相关的资源。 若要使用Azure CLI或Azure PowerShell删除资源组,请执行以下操作:
echo "Enter the Resource Group name:" &&
read resourceGroupName &&
az group delete --name $resourceGroupName &&
echo "Press [ENTER] to continue ..."
注释
删除资源组也会删除密钥保管库,但保管库随后进入软删除状态,并在保留期(默认情况下为 90 天)保持可恢复状态。 保管库名称在该时间段内保持全局保留状态,并且由于启用了清除保护,因此无法提前清除保管库。 对于标准密钥保管库,已软删除的保管库不会产生费用。 有关详细信息,请参阅 密钥保管库 软删除概述。
后续步骤
在本快速入门中,你已使用 ARM 模板创建了密钥保管库和证书,并验证了部署。 若要详细了解 密钥保管库 和 Azure 资源管理器,请继续阅读以下文章。
- 阅读 Azure 密钥保管库 概述
- 了解有关 Azure 资源管理器的详细信息
- 请参阅 密钥保管库 安全性概述