From 117d9a547d67dae3a759afe505fb99676e8c519f Mon Sep 17 00:00:00 2001 From: msmbaldwin <5092332+msmbaldwin@users.noreply.github.com> Date: Thu, 7 May 2026 12:11:06 -0700 Subject: [PATCH] Restore azuredeploy.json for key-vault-certificate-create Re-adds azuredeploy.json (compiled from main.bicep) which was incorrectly removed during the recent RBAC modernization PR. The 'Deploy to Azure' button in README.md links to this file. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../azuredeploy.json | 490 ++++++++++++++++++ 1 file changed, 490 insertions(+) create mode 100644 quickstarts/microsoft.keyvault/key-vault-certificate-create/azuredeploy.json diff --git a/quickstarts/microsoft.keyvault/key-vault-certificate-create/azuredeploy.json b/quickstarts/microsoft.keyvault/key-vault-certificate-create/azuredeploy.json new file mode 100644 index 000000000000..c5b9865564e5 --- /dev/null +++ b/quickstarts/microsoft.keyvault/key-vault-certificate-create/azuredeploy.json @@ -0,0 +1,490 @@ +{ + "$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": "14056312705210722600" + } + }, + "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, + "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]]" + } + } +} \ No newline at end of file