I need to create policy assignment which will block keyVault deployments without privateEndpoint configured. I tested built-in policy "[Preview]: Azure Key Vaults should use private link" with "Audit" effect and it works fine.
But when I change effect to "Deny" then my deployment is blocked as I'm deploying two resources (keyVault and privateEndpoint) separately. From what I understood from docs (https://learn.microsoft.com/en-us/azure/governance/policy/concepts/effects#deny) the resource is evaluated before sending to Resource provided. Which implicates the policy is not aware of private endpoint (as it's separate resource).
Have anyone faced similar problem and managed to handle it?
I'm pasting my template below:
resource keyVaultPrivateLink 'Microsoft.KeyVault/vaults#2019-09-01' = {
name: kvName
location: location
properties: {
enabledForTemplateDeployment: true
tenantId: tenant
enableRbacAuthorization: true
enablePurgeProtection: true
enableSoftDelete: true
networkAcls: {
bypass: 'AzureServices'
defaultAction: 'Deny'
virtualNetworkRules: [
{
id: subnetId
}
]
}
sku: {
name: 'standard'
family: 'A'
}
}
}
resource keyVaultPrivateEndpoint 'Microsoft.Network/privateEndpoints#2020-03-01' = {
name: 'pewetkvwetprivatelink'
location: location
properties: {
subnet: {
id: subnetId
}
privateLinkServiceConnections: [
{
name: 'kvwetprivatelink'
properties: {
privateLinkServiceId: keyVaultPrivateLink.id
groupIds: [
'vault'
]
}
}
]
}
}
The error code received:
{
"error": {
"code": "InvalidTemplateDeployment",
"message": "The template deployment failed because of policy violation. Please see details for more information.",
"details": [
{
"code": "RequestDisallowedByPolicy",
"target": "keyVault-name",
"message": "Resource 'kvwetprivatelink' was disallowed by policy. Policy identifiers: '[{\"policyAssignment\":{\"name\":\"Audit KeyVault Initiative\",\"id\":\"/subscriptions/***/providers/Microsoft.Authorization/policyAssignments/Audit KeyVault Initiative\"},\"policyDefinition\":{\"name\":\"[Preview]: Azure Key Vaults should use private link\",\"id\":\"/providers/Microsoft.Authorization/policyDefinitions/a6abeaec-4d90-4a02-805f-6b26c4d3fbe9\"},\"policySetDefinition\":{\"name\":\"Audit KeyVault Initiative\",\"id\":\"/subscriptions/***/providers/Microsoft.Authorization/policySetDefinitions/Audit KeyVault Initiative\"}}]'.",
"additionalInfo": [
{
"type": "PolicyViolation",
"info": {
"policyDefinitionDisplayName": "[Preview]: Azure Key Vaults should use private link",
"policySetDefinitionDisplayName": "Audit KeyVault Initiative",
"evaluationDetails": {
"evaluatedExpressions": [
{
"result": "True",
"expressionKind": "Field",
"expression": "type",
"path": "type",
"expressionValue": "Microsoft.KeyVault/vaults",
"targetValue": "Microsoft.KeyVault/vaults",
"operator": "Equals"
},
{
"result": "True",
"expressionKind": "Count",
"expression": "Microsoft.KeyVault/vaults/privateEndpointConnections[*]",
"path": "properties.privateEndpointConnections[*]",
"expressionValue": 0,
"targetValue": 1,
"operator": "Less"
}
]
},
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/a6abeaec-4d90-4a02-805f-6b26c4d3fbe9",
"policySetDefinitionId": "/subscriptions/***/providers/Microsoft.Authorization/policySetDefinitions/Audit KeyVault Initiative",
"policyDefinitionReferenceId": "[[Preview]: Azure Key Vaults should use private link",
"policySetDefinitionName": "Audit KeyVault Initiative",
"policyDefinitionName": "a6abeaec-4d90-4a02-805f-6b26c4d3fbe9",
"policyDefinitionEffect": "Deny",
"policyAssignmentId": "/subscriptions/***/providers/Microsoft.Authorization/policyAssignments/Audit KeyVault Initiative",
"policyAssignmentName": "Audit KeyVault Initiative",
"policyAssignmentDisplayName": "Audit KeyVault Initiative",
"policyAssignmentScope": "/subscriptions/***"
}
}
]
}
]
}
}
And policy definition:
{
"properties": {
"displayName": "[Preview]: Azure Key Vaults should use private link",
"policyType": "BuiltIn",
"mode": "Indexed",
"description": "Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to key vault, you can reduce data leakage risks. Learn more about private links at: https://aka.ms/akvprivatelink.",
"metadata": {
"version": "1.0.0-preview",
"category": "Key Vault",
"preview": true
},
"parameters": {
"effect": {
"type": "String",
"metadata": {
"displayName": "Effect",
"description": "Enable or disable the execution of the policy"
},
"allowedValues": [
"Audit",
"Deny",
"Disabled"
],
"defaultValue": "Audit"
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.KeyVault/vaults"
},
{
"count": {
"field": "Microsoft.KeyVault/vaults/privateEndpointConnections[*]",
"where": {
"field": "Microsoft.KeyVault/vaults/privateEndpointConnections[*].privateLinkServiceConnectionState.status",
"equals": "Approved"
}
},
"less": 1
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
},
"id": "/providers/Microsoft.Authorization/policyDefinitions/a6abeaec-4d90-4a02-805f-6b26c4d3fbe9",
"type": "Microsoft.Authorization/policyDefinitions",
"name": "a6abeaec-4d90-4a02-805f-6b26c4d3fbe9"
}
To clear the confusion here , As per the Microsoft Documentation shared by you it says :
When creating or updating a matched resource in a Resource Manager
mode, deny prevents the request before being sent to the Resource
Provider. The request is returned as a 403 (Forbidden).
Which means that neither the KeyVault or Private Endpoint can be created in the same template if the effect is set to Deny. The Effect should be Audit only for the policy to be effective properly.
I tested this using portal and its same as the template :
Scenario 1: Effect: Deny
Even if I add a private endpoint while deploying the Keyvault, the validation fails.
Scenario 2: Effect:Audit
I tried creating a keyvault without private endpoint evenif the validation passes , after clicking on create it fails as per policy.
If I create with a private endpoint then it successfully deploys.
Related
I am trying to write an Azure Policy that checks if a Azure key has an expiry date, if it does not then I want to do a DeployIfNotExists effect to set one. However I am getting a "ResourceNotFound" error.
Note: The "if" statement without the "then" statement works fine, when I run this policy it shows me which keys do not have a expiration date. Getting the issue when I add in the deployifnotexist effect.
{
"mode": "All",
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.KeyVault/vaults/keys"
},
{
"field": "Microsoft.KeyVault/vaults/keys/attributes.exp",
"exists": false
}
]
},
"then": {
"effect": "deployIfNotExists",
"details": {
"type": "Microsoft.KeyVault/vaults/keys",
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635"
],
"deployment": {
"properties": {
"mode": "incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.KeyVault/vaults/keys",
"apiVersion": "2021-06-01-preview",
"properties": {
"exp": "10000"
}
}
]
}
}
}
}
}
},
"parameters": {}
}
Here you are working at the Data layer of the Key Vault, what is inside of it (Keys, Secrets, Certificates).
In that case, when it is not about the infrastructure as such (the configuration of the Key Vault itself), you have to use the Microsoft.KeyVault.Data mode for your custom policy instead of All.
That said, DeployIfNotExist policies are not yet supported - see official documentation about Azure Policy for Key Vault. You can only Audit or Deny.
Trying to deploy Azure Dashboard through ARM template and getting an issue after deployment (see screenshot below).
The following document was used to construct template: Azure Dashboard
ARM template looks like:
"log-analytics-workspace-id": {
"type": "string",
"defaultValue": "/subscriptions/xxxx-xxxx-xxxx-xxxx-xxxx/resourcegroups/rg-ProjectX-dev-infra",
"allowedValues": [
"/subscriptions/xxxx-xxxx-xxxx-xxxx-xxxx/resourcegroups/rg-ProjectX-dev-infra"
],
"metadata": {
"description": "The resource ID for an existing Log Analytics workspace."
}
}
"variables": {
"la-name": "[concat('la', '-', parameters('base-name'), '-', 'workspace')]",
{
"name": "Scope",
"value": {
"resourceIds": "[resourceId('Microsoft.Operationalinsights/workspaces', parameters('log-analytics-workspace-id'), variables('la-name'))]"
},
"isOptional": true
}
resourceIds value defined like:
"name": "Scope",
"value": {
"resourceIds": "[parameters('log-analytics-workspace-id')]"
},
"isOptional": true
},
...and paremeter defined log-analytics-workspace-id:
"log-analytics-workspace-id": {
"type": "string",
"defaultValue": "/subscriptions/xxxx-xxxx-xxxx-xxxx-xxxx/resourcegroups/rg-ProjectX-dev-infra/providers/microsoft.operationalinsights/workspaces/la-ProjectX-dev-workspace",
"allowedValues": [
"/subscriptions/xxxx-xxxx-xxxx-xxxx-xxxx/resourcegroups/rg-ProjectX-dev-infra/providers/microsoft.operationalinsights/workspaces/la-ProjectX-dev-workspace"
],
"metadata": {
"description": "The resource ID for an existing Log Analytics workspace."
}
}
Azure Dashboard has deployed successfully, however, the dashboard is not operational yet:
Azure dashboard view
Fixed an issue by combining the value in array:
{
"name": "Scope",
"value": {
"resourceIds": [
"[parameters('log-analytics-workspace-id')]"
]
}
},
I am trying to understand how Management group policies works but deploying some policies.
I have this ARM template, which its purpose it to block specific resources from being created. Which, in my case works, but I would like to deny the creation of storage account only if specific sku.name is selected
this is the azure policy.
{
"properties": {
"displayName": "Not allowed resource types",
"policyType": "BuiltIn",
"mode": "All",
"description": "This policy enables you to specify the resource types that your organization cannot deploy.",
"parameters": {
"listOfResourceTypesNotAllowed": {
"type": "Array",
"metadata": {
"description": "The list of resource types that cannot be deployed.",
"displayName": "Not allowed resource types",
"strongType": "resourceTypes"
}
}
},
"policyRule": {
"if": {
"field": "type",
"in": "[parameters('listOfResourceTypesNotAllowed')]"
},
"then": {
"effect": "Deny"
}
}
},
"id": "/providers/Microsoft.Authorization/policyDefinitions/6c112d4e-5bc7-47ae-a041-ea2d9dccd749",
"type": "Microsoft.Authorization/policyDefinitions",
"name": "6c112d4e-5bc7-47ae-a041-ea2d9dccd749"
}
and this my parameters:
{
"listOfResourceTypesNotAllowed": {
"type": "Array",
"metadata": {
"description": "The list of resource types that cannot be deployed.",
"displayName": "Not allowed resource types",
"strongType": "resourceTypes"
},
"allowedValues": [
"Microsoft.DocumentDB/databaseAccounts",
"Microsoft.Storage/storageAccounts"
]
}
}
and my rules:
{
"if": {
"field": "type",
"in": "[parameters('listOfResourceTypesNotAllowed')]"
},
"then": {
"effect": "Deny"
}
}
Can anyone help me to understand how can this be achieved please?
Thank you so much for anyone who can spend some time to help me to understand this type of deployment
You can use the below policy defination for allowing only allowed sku types of storage accounts to be deployed in your subscription:
{
"properties": {
"displayName": "Storage accounts should be limited by allowed SKUs",
"policyType": "BuiltIn",
"mode": "Indexed",
"description": "Restrict the set of storage account SKUs that your organization can deploy.",
"metadata": {
"version": "1.1.0",
"category": "Storage"
},
"parameters": {
"effect": {
"type": "String",
"metadata": {
"displayName": "Effect",
"description": "Enable or disable the execution of the audit policy"
},
"allowedValues": [
"Audit",
"Deny",
"Disabled"
],
"defaultValue": "Deny"
},
"listOfAllowedSKUs": {
"type": "Array",
"metadata": {
"description": "The list of SKUs that can be specified for storage accounts.",
"displayName": "Allowed SKUs",
"strongType": "StorageSKUs"
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
{
"not": {
"field": "Microsoft.Storage/storageAccounts/sku.name",
"in": "[parameters('listOfAllowedSKUs')]"
}
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
},
"id": "/providers/Microsoft.Authorization/policyDefinitions/7433c107-6db4-4ad1-b57a-a76dce0154a1",
"type": "Microsoft.Authorization/policyDefinitions",
"name": "7433c107-6db4-4ad1-b57a-a76dce0154a1"
}
Reference:
List of built-in policy definitions - Azure Policy | Microsoft Docs
Storage accounts should be limited by allowed SKUs- policy
There is no support from Azure for Azure Key vault backup(existing options are error prone when it comes to automation). There is soft delete and I can reset passwords and put it back in keyvault, in case something goes wrong. So it seems okay still as an alternative to backup I would like to take a screenshot of the Secret Names (not values) and put that image in storage account. Is this safe? The reason why I do this is because it will be easy to recreate the secrets in case key-vault goes down(.5 % chance).
You can definitely use Soft Delete feature as an alternative. Apart from that, in case KeyVault goes down and you want to recreate the secrets, it's easier and safer to setup ARM template and ADO pipeline to achieve your goal with restricted access to the ADO (only people who are part of your organization in ADO can see the pipeline).
The ARM template for Key Vault looks like this:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"keyVaultName": {
"type": "string",
"metadata": {
"description": "Specifies the name of the key vault."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"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."
}
},
"secretName": {
"type": "string",
"metadata": {
"description": "Specifies the name of the secret that you want to create."
}
},
"secretValue": {
"type": "securestring",
"metadata": {
"description": "Specifies the value of the secret that you want to create."
}
}
},
"resources": [
{
"type": "Microsoft.KeyVault/vaults",
"name": "[parameters('keyVaultName')]",
"apiVersion": "2019-09-01",
"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')]"
}
}
],
"sku": {
"name": "[parameters('skuName')]",
"family": "A"
},
"networkAcls": {
"defaultAction": "Allow",
"bypass": "AzureServices"
}
}
},
{
"type": "Microsoft.KeyVault/vaults/secrets",
"name": "[concat(parameters('keyVaultName'), '/', parameters('secretName'))]",
"apiVersion": "2019-09-01",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]"
],
"properties": {
"value": "[parameters('secretValue')]"
}
}
]
}
The ADO Release pipeline will look like this:
Example build pipeline for .NET core solution repo:
Then, you can use Azure Resource Group Deployment task in your ADO release pipeline.
Azure Key Vault Backup to another Key Vault using LogicApp
Pre-Requisites
Enable LogicApp system assigned managed identity.
Two key vault in same subscription and geography.
Add LogicApp objectID in key vault access policy with following key and secret permissions,
backup,list(source key vault)
restore(destination key vault)
Limitation
Source and Destination key vault should be in same subscription and geography.
Steps
Design
Step1
Paste output generated from Step1 in Parse JSON to generate schema
Step2
Step3
Step4
above steps are same for secrets backup
References
Key Vault REST
LogicApp Backup/Restore using Storage Account
azureazure-keyvaultazure-logic-apps
We are using gitlab pipeline to spin infrastructure like VM/Service bus and other resources through terraform in Azure cloud. Many time Developers forget to tag what purpose they spin off resource. Due to lack of this info, we are unable to find resources and their purpose.
Is there any way in gitlab pipeline through variable or any other way without tag pipeline will fail? Like enforcement to use tag while spinning of any infrastructure through gitlab pipeline.
I am looking for any configuration or enforcement policy in gitlab
you can use Azure policy for that. Enforce tag:
{
"properties": {
"displayName": "Enforce tag and its value",
"policyType": "BuiltIn",
"description": "Enforces a required tag and its value.",
"parameters": {
"tagName": {
"type": "String",
"metadata": {
"description": "Name of the tag, such as costCenter"
}
},
"tagValue": {
"type": "String",
"metadata": {
"description": "Value of the tag, such as headquarter"
}
}
},
"policyRule": {
"if": {
"not": {
"field": "[concat('tags[', parameters('tagName'), ']')]",
"equals": "[parameters('tagValue')]"
}
},
"then": {
"effect": "deny"
}
}
},
"id": "/providers/Microsoft.Authorization/policyDefinitions/1e30110a-5ceb-460c-a204-c1c3969c6d62",
"type": "Microsoft.Authorization/policyDefinitions",
"name": "1e30110a-5ceb-460c-a204-c1c3969c6d62"
}
Links:
https://learn.microsoft.com/en-us/azure/governance/policy/samples/enforce-tag-value
https://learn.microsoft.com/en-us/azure/governance/policy/samples/enforce-tag-on-resource-groups