diff --git a/modules/Microsoft.KeyVault/vaults/.test/common/dependencies.bicep b/modules/Microsoft.KeyVault/vaults/.test/common/dependencies.bicep index 064a1f10d8..10e0010649 100644 --- a/modules/Microsoft.KeyVault/vaults/.test/common/dependencies.bicep +++ b/modules/Microsoft.KeyVault/vaults/.test/common/dependencies.bicep @@ -7,6 +7,12 @@ param virtualNetworkName string @description('Required. The name of the Managed Identity to create.') param managedIdentityName string +@description('Optional. The name of the policy assignment.') +param policyAssignmentName string = 'KeyVaultsShouldBeBackedbyHSM' + +@description('Optional. The policy definition Id to be assigned.') +param policyDefinitionId string = '/providers/Microsoft.Authorization/policyDefinitions/587c79fe-dd04-4a5e-9d0b-f89598c7261b' // Key vaults should be backed by a hardware security module (HSM). + var addressPrefix = '10.0.0.0/16' resource virtualNetwork 'Microsoft.Network/virtualNetworks@2022-01-01' = { @@ -39,6 +45,27 @@ resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018- location: location } +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2022-06-01' = { + name: policyAssignmentName + scope: resourceGroup() + location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + policyDefinitionId: policyDefinitionId + enforcementMode: 'Default' + parameters: { + effect: { + value: 'Deny' + } + } + } +} + resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { name: 'privatelink.vaultcore.azure.net' location: 'global' @@ -63,3 +90,6 @@ output managedIdentityPrincipalId string = managedIdentity.properties.principalI @description('The resource ID of the created Private DNS Zone.') output privateDNSResourceId string = privateDNSZone.id + +@description('The resource ID of the Policy Assignment.') +output policyAssignmentId string = policyAssignment.id diff --git a/modules/Microsoft.KeyVault/vaults/.test/common/deploy.test.bicep b/modules/Microsoft.KeyVault/vaults/.test/common/deploy.test.bicep index b01982f72d..72b739a5be 100644 --- a/modules/Microsoft.KeyVault/vaults/.test/common/deploy.test.bicep +++ b/modules/Microsoft.KeyVault/vaults/.test/common/deploy.test.bicep @@ -153,6 +153,16 @@ module testDeployment '../../deploy.bicep' = { } ] } + policyExemptions: [ + { + name: '<>${serviceShort}001-PolicyExemption001' + displayName: '<>${serviceShort}001 Policy Exception' + description: 'Test Policy Exemption 1' + assignmentScopeValidation: 'DoNotValidate' + policyAssignmentId: nestedDependencies.outputs.policyAssignmentId + exemptionCategory: 'Waiver' + } + ] privateEndpoints: [ { privateDnsZoneGroup: { diff --git a/modules/Microsoft.KeyVault/vaults/deploy.bicep b/modules/Microsoft.KeyVault/vaults/deploy.bicep index 7f23143f12..831e405079 100644 --- a/modules/Microsoft.KeyVault/vaults/deploy.bicep +++ b/modules/Microsoft.KeyVault/vaults/deploy.bicep @@ -85,6 +85,17 @@ param diagnosticEventHubName string = '' @description('Optional. Specify the type of lock.') param lock string = '' +@description('''Optional. Array of policy exemption objects that contain the \'name\' and \'policyAssignmentId\' to policy exemptions on this resource. + +Exemptions have extra security measures because of the impact of granting an exemption. + +Beyond requiring the Microsoft.Authorization/policyExemptions/write operation on the resource hierarchy or individual resource, +the creator of an exemption must have the exempt/Action verb on the target assignment which could be at the Management Group, Subscription, or Resource Group levels. + +The built-in roles Resource Policy Contributor and Security Admin both have the read and write permissions. +''') +param policyExemptions array = [] + @description('Optional. Array of role assignment objects that contain the \'roleDefinitionIdOrName\' and \'principalId\' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') param roleAssignments array = [] @@ -295,6 +306,20 @@ module keyVault_privateEndpoints '../../Microsoft.Network/privateEndpoints/deplo } }] +resource keyVault_policyExemptions 'Microsoft.Authorization/policyExemptions@2022-07-01-preview' = [for policyExemption in policyExemptions: if (!empty(policyExemptions)) { + name: policyExemption.name + properties: { + assignmentScopeValidation: contains(policyExemption, 'assignmentScopeValidation') ? policyExemption.assignmentScopeValidation : '' + displayName: contains(policyExemption, 'displayName') ? policyExemption.description : '' + description: contains(policyExemption, 'description') ? policyExemption.description : '' + metadata: contains(policyExemption, 'metadata') ? policyExemption.metadata : {} + policyAssignmentId: policyExemption.policyAssignmentId + policyDefinitionReferenceIds: contains(policyExemption, 'policyDefinitionReferenceIds') ? policyExemption.policyDefinitionReferenceIds : null + exemptionCategory: contains(policyExemption, 'exemptionCategory') ? policyExemption.exemptionCategory : null + expiresOn: contains(policyExemption, 'expiresOn') ? policyExemption.expiresOn : '' + } + scope: keyVault +}] module keyVault_roleAssignments '.bicep/nested_roleAssignments.bicep' = [for (roleAssignment, index) in roleAssignments: { name: '${uniqueString(deployment().name, location)}-KeyVault-Rbac-${index}' params: { diff --git a/modules/Microsoft.KeyVault/vaults/readme.md b/modules/Microsoft.KeyVault/vaults/readme.md index 37372e309c..3a902695e2 100644 --- a/modules/Microsoft.KeyVault/vaults/readme.md +++ b/modules/Microsoft.KeyVault/vaults/readme.md @@ -15,6 +15,7 @@ This module deploys a key vault and its child resources. | Resource Type | API Version | | :-- | :-- | | `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/policyExemptions` | [2022-07-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-07-01-preview/policyExemptions) | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | | `Microsoft.KeyVault/vaults` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults) | @@ -57,6 +58,7 @@ This module deploys a key vault and its child resources. | `location` | string | `[resourceGroup().location]` | | Location for all resources. | | `lock` | string | `''` | `['', CanNotDelete, ReadOnly]` | Specify the type of lock. | | `networkAcls` | object | `{object}` | | Service endpoint object information. For security reasons, it is recommended to set the DefaultAction Deny. | +| `policyExemptions` | array | `[]` | | Array of policy exemption objects that contain the \'name\' and \'policyAssignmentId\' to policy exemptions on this resource.

Exemptions have extra security measures because of the impact of granting an exemption.

Beyond requiring the Microsoft.Authorization/policyExemptions/write operation on the resource hierarchy or individual resource,

the creator of an exemption must have the exempt/Action verb on the target assignment which could be at the Management Group, Subscription, or Resource Group levels.

The built-in roles Resource Policy Contributor and Security Admin both have the read and write permissions.

| | `privateEndpoints` | array | `[]` | | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | | `publicNetworkAccess` | string | `''` | `['', Disabled, Enabled]` | Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set. | | `roleAssignments` | array | `[]` | | Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | @@ -506,6 +508,16 @@ module vaults './Microsoft.KeyVault/vaults/deploy.bicep' = { } ] } + policyExemptions: [ + { + assignmentScopeValidation: 'DoNotValidate' + description: 'Test Policy Exemption 1' + displayName: '<>kvvcom001 Policy Exception' + exemptionCategory: 'Waiver' + name: '<>kvvcom001-PolicyExemption001' + policyAssignmentId: '' + } + ] privateEndpoints: [ { privateDnsZoneGroup: { @@ -690,6 +702,18 @@ module vaults './Microsoft.KeyVault/vaults/deploy.bicep' = { ] } }, + "policyExemptions": { + "value": [ + { + "assignmentScopeValidation": "DoNotValidate", + "description": "Test Policy Exemption 1", + "displayName": "<>kvvcom001 Policy Exception", + "exemptionCategory": "Waiver", + "name": "<>kvvcom001-PolicyExemption001", + "policyAssignmentId": "" + } + ] + }, "privateEndpoints": { "value": [ { diff --git a/modules/Microsoft.Storage/storageAccounts/.test/common/dependencies.bicep b/modules/Microsoft.Storage/storageAccounts/.test/common/dependencies.bicep index d130bdb97d..ea17fb196b 100644 --- a/modules/Microsoft.Storage/storageAccounts/.test/common/dependencies.bicep +++ b/modules/Microsoft.Storage/storageAccounts/.test/common/dependencies.bicep @@ -7,6 +7,12 @@ param virtualNetworkName string @description('Required. The name of the Managed Identity to create.') param managedIdentityName string +@description('Optional. The name of the policy assignment.') +param policyAssignmentName string = 'StorAcctsAccessfromMSServices' + +@description('Optional. The policy definition Id to be assigned.') +param policyDefinitionId string = '/providers/Microsoft.Authorization/policyDefinitions/c9d007d0-c057-4772-b18c-01e546713bcd' //Storage accounts should allow access from trusted Microsoft services + var addressPrefix = '10.0.0.0/16' resource virtualNetwork 'Microsoft.Network/virtualNetworks@2022-01-01' = { @@ -55,6 +61,27 @@ resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018- location: location } +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2022-06-01' = { + name: policyAssignmentName + scope: resourceGroup() + location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + policyDefinitionId: policyDefinitionId + enforcementMode: 'Default' + parameters: { + effect: { + value: 'Deny' + } + } + } +} + @description('The resource ID of the created Virtual Network Subnet.') output subnetResourceId string = virtualNetwork.properties.subnets[0].id @@ -66,3 +93,6 @@ output managedIdentityResourceId string = managedIdentity.id @description('The resource ID of the created Private DNS Zone.') output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The resource ID of the Policy Assignment.') +output policyAssignmentId string = policyAssignment.id diff --git a/modules/Microsoft.Storage/storageAccounts/.test/common/deploy.test.bicep b/modules/Microsoft.Storage/storageAccounts/.test/common/deploy.test.bicep index 4fe2601520..152e48e48d 100644 --- a/modules/Microsoft.Storage/storageAccounts/.test/common/deploy.test.bicep +++ b/modules/Microsoft.Storage/storageAccounts/.test/common/deploy.test.bicep @@ -69,6 +69,16 @@ module testDeployment '../../deploy.bicep' = { enableHierarchicalNamespace: true enableSftp: true enableNfsV3: true + policyExemptions: [ + { + name: '<>${serviceShort}001-PolicyExemption001' + displayName: '<>${serviceShort}001 Policy Exception' + description: 'Test Policy Exemption 1' + assignmentScopeValidation: 'DoNotValidate' + policyAssignmentId: nestedDependencies.outputs.policyAssignmentId + exemptionCategory: 'Waiver' + } + ] privateEndpoints: [ { service: 'blob' diff --git a/modules/Microsoft.Storage/storageAccounts/deploy.bicep b/modules/Microsoft.Storage/storageAccounts/deploy.bicep index 024bc67e2e..77cec283f9 100644 --- a/modules/Microsoft.Storage/storageAccounts/deploy.bicep +++ b/modules/Microsoft.Storage/storageAccounts/deploy.bicep @@ -5,6 +5,17 @@ param name string @description('Optional. Location for all resources.') param location string = resourceGroup().location +@description('''Optional. Array of policy exemption objects that contain the \'name\' and \'policyAssignmentId\' to policy exemptions on this resource. + +Exemptions have extra security measures because of the impact of granting an exemption. + +Beyond requiring the Microsoft.Authorization/policyExemptions/write operation on the resource hierarchy or individual resource, +the creator of an exemption must have the exempt/Action verb on the target assignment which could be at the Management Group, Subscription, or Resource Group levels. + +The built-in roles Resource Policy Contributor and Security Admin both have the read and write permissions. +''') +param policyExemptions array = [] + @description('Optional. Array of role assignment objects that contain the \'roleDefinitionIdOrName\' and \'principalId\' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') param roleAssignments array = [] @@ -338,6 +349,21 @@ module storageAccount_roleAssignments '.bicep/nested_roleAssignments.bicep' = [f } }] +resource storageAccount_policyExemptions 'Microsoft.Authorization/policyExemptions@2022-07-01-preview' = [for policyExemption in policyExemptions: if (!empty(policyExemptions)) { + name: policyExemption.name + properties: { + assignmentScopeValidation: contains(policyExemption, 'assignmentScopeValidation') ? policyExemption.assignmentScopeValidation : '' + displayName: contains(policyExemption, 'displayName') ? policyExemption.description : '' + description: contains(policyExemption, 'description') ? policyExemption.description : '' + metadata: contains(policyExemption, 'metadata') ? policyExemption.metadata : {} + policyAssignmentId: policyExemption.policyAssignmentId + policyDefinitionReferenceIds: contains(policyExemption, 'policyDefinitionReferenceIds') ? policyExemption.policyDefinitionReferenceIds : null + exemptionCategory: contains(policyExemption, 'exemptionCategory') ? policyExemption.exemptionCategory : null + expiresOn: contains(policyExemption, 'expiresOn') ? policyExemption.expiresOn : '' + } + scope: storageAccount +}] + module storageAccount_privateEndpoints '../../Microsoft.Network/privateEndpoints/deploy.bicep' = [for (privateEndpoint, index) in privateEndpoints: { name: '${uniqueString(deployment().name, location)}-StorageAccount-PrivateEndpoint-${index}' params: { diff --git a/modules/Microsoft.Storage/storageAccounts/readme.md b/modules/Microsoft.Storage/storageAccounts/readme.md index fefef84885..4370216671 100644 --- a/modules/Microsoft.Storage/storageAccounts/readme.md +++ b/modules/Microsoft.Storage/storageAccounts/readme.md @@ -16,6 +16,7 @@ This module is used to deploy a storage account, with the ability to deploy 1 or | Resource Type | API Version | | :-- | :-- | | `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/policyExemptions` | [2022-07-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-07-01-preview/policyExemptions) | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | | `Microsoft.Network/privateEndpoints` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-07-01/privateEndpoints) | @@ -85,6 +86,7 @@ This module is used to deploy a storage account, with the ability to deploy 1 or | `managementPolicyRules` | array | `[]` | | The Storage Account ManagementPolicies Rules. | | `minimumTlsVersion` | string | `'TLS1_2'` | `[TLS1_0, TLS1_1, TLS1_2]` | Set the minimum TLS version on request to storage. | | `networkAcls` | object | `{object}` | | Networks ACLs, this value contains IPs to whitelist and/or Subnet information. For security reasons, it is recommended to set the DefaultAction Deny. | +| `policyExemptions` | array | `[]` | | Array of policy exemption objects that contain the \'name\' and \'policyAssignmentId\' to policy exemptions on this resource.

Exemptions have extra security measures because of the impact of granting an exemption.

Beyond requiring the Microsoft.Authorization/policyExemptions/write operation on the resource hierarchy or individual resource,

the creator of an exemption must have the exempt/Action verb on the target assignment which could be at the Management Group, Subscription, or Resource Group levels.

The built-in roles Resource Policy Contributor and Security Admin both have the read and write permissions.

| | `privateEndpoints` | array | `[]` | | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | | `publicNetworkAccess` | string | `''` | `['', Disabled, Enabled]` | Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set. | | `queueServices` | _[queueServices](queueServices/readme.md)_ object | `{object}` | | Queue service and queues to create. | @@ -531,6 +533,16 @@ module storageAccounts './Microsoft.Storage/storageAccounts/deploy.bicep' = { } ] } + policyExemptions: [ + { + assignmentScopeValidation: 'DoNotValidate' + description: 'Test Policy Exemption 1' + displayName: '<>ssacom001 Policy Exception' + exemptionCategory: 'Waiver' + name: '<>ssacom001-PolicyExemption001' + policyAssignmentId: '' + } + ] privateEndpoints: [ { privateDnsZoneGroup: { @@ -758,6 +770,18 @@ module storageAccounts './Microsoft.Storage/storageAccounts/deploy.bicep' = { ] } }, + "policyExemptions": { + "value": [ + { + "assignmentScopeValidation": "DoNotValidate", + "description": "Test Policy Exemption 1", + "displayName": "<>ssacom001 Policy Exception", + "exemptionCategory": "Waiver", + "name": "<>ssacom001-PolicyExemption001", + "policyAssignmentId": "" + } + ] + }, "privateEndpoints": { "value": [ {