Azure Key Vault 是一項雲端服務,提供一個安全的秘密儲存,例如金鑰、密碼和憑證。 本快速入門重點介紹部署 Azure Resource Manager 範本(ARM 範本)以建立金鑰庫與自簽憑證的過程。
Azure Resource Manager 模板 是一個 JavaScript 物件符號(JSON)檔案,用來定義你專案的基礎架構與設定。 範本使用宣告式語法。 您可以描述預期的部署,而不需要撰寫程式設計命令順序來建立部署。
如果你的環境符合前提條件,且熟悉使用 ARM 範本,請選擇 部署到 Azure 按鈕。 範本會在 Azure 入口網站中開啟。
先決條件
以下是完成本文的步驟:
- 如果您沒有 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 並開啟範本。 範本會建立金鑰保險庫和憑證。
選取或輸入下列值。 除非特別指定,否則就用預設值。
- 訂用帳戶:選取 Azure 訂用帳戶。
- 資源群組:選取 [新建],輸入資源群組的唯一名稱,然後選取 [確認]。
- 區域:選擇地點。 例如,美國中部。
-
保險庫名稱:輸入金鑰保險庫名稱,且必須在命名空間內
vault.azure.net全域唯一。 - 證書名稱:輸入證書名稱。 例如, 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在金鑰保存庫上將 金鑰保存庫 Certificates Officer 角色指派給自己:
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)Note
角色指派可能需要一兩分鐘才會生效。
檢閱已部署的資源
你可以使用 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 ..."
Note
刪除資源群組也會刪除金鑰庫,但金庫會進入軟刪除狀態,並在保留期間(預設為 90 天)內仍可恢復。 在此期間,該保存庫名稱仍會在全域保留,而且因為已啟用清除保護,所以無法提前清除該保存庫。 對於標準金鑰保存庫,虛刪除的保存庫不會產生費用。 更多資訊請參見 金鑰保存庫 軟刪除概覽。
下一步
在這個快速入門中,你用 ARM 範本建立了金鑰保險庫和憑證,並驗證了部署。 想了解更多關於 金鑰保存庫 和 Azure Resource Manager 的資訊,請繼續閱讀以下文章。
- 閱讀 Azure Key Vault 概述
- 了解更多關於Azure Resource Manager
- 請參閱 金鑰保存庫 安全性概觀