{ "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "projectName": { "type": "string", "metadata": { "description": "Specifies a project name that is used for generating resource group name and resource names." } }, "location": { "type": "string", "metadata": { "description": "Specifies the Azure location where the key vault should be created." } }, "enabledForDeployment": { "type": "bool", "defaultValue": false, "allowedValues": [ true, false ], "metadata": { "description": "Specifies whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key vault." } }, "enabledForDiskEncryption": { "type": "bool", "defaultValue": false, "allowedValues": [ true, false ], "metadata": { "description": "Specifies whether Azure Disk Encryption is permitted to retrieve secrets from the vault and unwrap keys." } }, "enabledForTemplateDeployment": { "type": "bool", "defaultValue": false, "allowedValues": [ true, false ], "metadata": { "description": "Specifies whether Azure Resource Manager is permitted to retrieve secrets from the key vault." } }, "tenantId": { "type": "string", "defaultValue": "[subscription().tenantId]", "metadata": { "description": "Specifies the Azure Active Directory tenant ID that should be used for authenticating requests to the key vault. Get it by using Get-AzSubscription cmdlet." } }, "objectId": { "type": "string", "metadata": { "description": "Specifies the object ID of a user, service principal or security group in the Azure Active Directory tenant for the vault. The object ID must be unique for the list of access policies. Get it by using Get-AzADUser or Get-AzADServicePrincipal cmdlets." } }, "keysPermissions": { "type": "array", "defaultValue": [ "list" ], "metadata": { "description": "Specifies the permissions to keys in the vault. Valid values are: all, encrypt, decrypt, wrapKey, unwrapKey, sign, verify, get, list, create, update, import, delete, backup, restore, recover, and purge." } }, "secretsPermissions": { "type": "array", "defaultValue": [ "list" ], "metadata": { "description": "Specifies the permissions to secrets in the vault. Valid values are: all, get, list, set, delete, backup, restore, recover, and purge." } }, "skuName": { "type": "string", "defaultValue": "Standard", "allowedValues": [ "Standard", "Premium" ], "metadata": { "description": "Specifies whether the key vault is a standard vault or a premium vault." } }, "identityId": { "type": "string", "metadata": { "description": "Specifies the ID of the user-assigned managed identity." } }, "certificatesPermissions": { "type": "array", "defaultValue": [ "get", "list", "update", "create" ], "metadata": { "description": "Specifies the permissions to certificates in the vault. Valid values are: all, get, list, update, create, import, delete, recover, backup, restore, manage contacts, manage certificate authorities, get certificate authorities, list certificate authorities, set certificate authorities, delete certificate authorities." } }, "certificateName": { "type": "string", "defaultValue": "DeploymentScripts2020" }, "subjectName": { "type": "string", "defaultValue": "CN=contoso.com" }, "utcValue": { "type": "string", "defaultValue": "[utcNow()]" } }, "variables": { "resourceGroupName": "[concat(parameters('projectName'), 'rg')]", "keyVaultName": "[concat(parameters('projectName'), 'kv')]" }, "resources": [ { "type": "Microsoft.Resources/resourceGroups", "apiVersion": "2021-04-01", "name": "[variables('resourceGroupName')]", "location": "[parameters('location')]", "properties": {} }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2021-04-01", "name": "KeyVaultDeployment", "resourceGroup": "[variables('resourceGroupName')]", "dependsOn": [ "[resourceId('Microsoft.Resources/resourceGroups/', variables('resourceGroupName'))]" ], "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.KeyVault/vaults", "name": "[variables('keyVaultName')]", "apiVersion": "2021-06-01-preview", "location": "[parameters('location')]", "properties": { "enabledForDeployment": "[parameters('enabledForDeployment')]", "enabledForDiskEncryption": "[parameters('enabledForDiskEncryption')]", "enabledForTemplateDeployment": "[parameters('enabledForTemplateDeployment')]", "tenantId": "[parameters('tenantId')]", "accessPolicies": [ { "objectId": "[parameters('objectId')]", "tenantId": "[parameters('tenantId')]", "permissions": { "keys": "[parameters('keysPermissions')]", "secrets": "[parameters('secretsPermissions')]", "certificates": "[parameters('certificatesPermissions')]" } }, { "objectId": "[reference(parameters('identityId'), '2018-11-30').principalId]", "tenantId": "[parameters('tenantId')]", "permissions": { "keys": "[parameters('keysPermissions')]", "secrets": "[parameters('secretsPermissions')]", "certificates": "[parameters('certificatesPermissions')]" } } ], "sku": { "name": "[parameters('skuName')]", "family": "A" }, "networkAcls": { "defaultAction": "Allow", "bypass": "AzureServices" } } }, { "type": "Microsoft.Resources/deploymentScripts", "apiVersion": "2020-10-01", "name": "createAddCertificate", "location": "[parameters('location')]", "dependsOn": [ "[variables('keyVaultName')]" ], "identity": { "type": "UserAssigned", "userAssignedIdentities": { "[parameters('identityId')]": { } } }, "kind": "AzurePowerShell", "properties": { "forceUpdateTag": "[parameters('utcValue')]", "azPowerShellVersion": "8.3", "timeout": "PT30M", "arguments": "[format(' -vaultName {0} -certificateName {1} -subjectName {2}', variables('keyVaultName'), parameters('certificateName'), parameters('subjectName'))]", // can pass an arguement string, double quotes must be escaped "scriptContent": " param( [string] [Parameter(Mandatory=$true)] $vaultName, [string] [Parameter(Mandatory=$true)] $certificateName, [string] [Parameter(Mandatory=$true)] $subjectName ) $ErrorActionPreference = 'Stop' $DeploymentScriptOutputs = @{} $existingCert = Get-AzKeyVaultCertificate -VaultName $vaultName -Name $certificateName if ($existingCert -and $existingCert.Certificate.Subject -eq $subjectName) { Write-Host 'Certificate $certificateName in vault $vaultName is already present.' $DeploymentScriptOutputs['certThumbprint'] = $existingCert.Thumbprint $existingCert | Out-String } else { $policy = New-AzKeyVaultCertificatePolicy -SubjectName $subjectName -IssuerName Self -ValidityInMonths 12 -Verbose # private key is added as a secret that can be retrieved in the ARM template Add-AzKeyVaultCertificate -VaultName $vaultName -Name $certificateName -CertificatePolicy $policy -Verbose $newCert = Get-AzKeyVaultCertificate -VaultName $vaultName -Name $certificateName # it takes a few seconds for KeyVault to finish $tries = 0 do { Write-Host 'Waiting for certificate creation completion...' Start-Sleep -Seconds 10 $operation = Get-AzKeyVaultCertificateOperation -VaultName $vaultName -Name $certificateName $tries++ if ($operation.Status -eq 'failed') { throw 'Creating certificate $certificateName in vault $vaultName failed with error $($operation.ErrorMessage)' } if ($tries -gt 120) { throw 'Timed out waiting for creation of certificate $certificateName in vault $vaultName' } } while ($operation.Status -ne 'completed') $DeploymentScriptOutputs['certThumbprint'] = $newCert.Thumbprint $newCert | Out-String } ", "cleanupPreference": "OnSuccess", "retentionInterval": "P1D" } } ] } } } ] }