diff --git a/.azuredevops/modulePipelines/ms.purview.accounts.yml b/.azuredevops/modulePipelines/ms.purview.accounts.yml new file mode 100644 index 0000000000..ecc59bec88 --- /dev/null +++ b/.azuredevops/modulePipelines/ms.purview.accounts.yml @@ -0,0 +1,50 @@ +name: 'Purview - Accounts' + +parameters: + - name: staticValidation + displayName: Execute static validation + type: boolean + default: true + - name: deploymentValidation + displayName: Execute deployment validation + type: boolean + default: true + - name: removeDeployment + displayName: Remove deployed module + type: boolean + default: true + - name: prerelease + displayName: Publish prerelease module + type: boolean + default: false + +pr: none + +trigger: + batch: true + branches: + include: + - main + paths: + include: + - '/.azuredevops/modulePipelines/ms.purview.accounts.yml' + - '/.azuredevops/pipelineTemplates/*.yml' + - '/modules/Microsoft.Purview/accounts/*' + - '/utilities/pipelines/*' + exclude: + - '/utilities/pipelines/deploymentRemoval/*' + - '/**/*.md' + +variables: + - template: '../../settings.yml' + - group: 'PLATFORM_VARIABLES' + - name: modulePath + value: '/modules/Microsoft.Purview/accounts' + +stages: + - template: /.azuredevops/pipelineTemplates/stages.module.yml + parameters: + staticValidation: '${{ parameters.staticValidation }}' + deploymentValidation: '${{ parameters.deploymentValidation }}' + removeDeployment: '${{ parameters.removeDeployment }}' + prerelease: '${{ parameters.prerelease }}' diff --git a/.github/workflows/ms.purview.accounts.yml b/.github/workflows/ms.purview.accounts.yml new file mode 100644 index 0000000000..5adf1336c0 --- /dev/null +++ b/.github/workflows/ms.purview.accounts.yml @@ -0,0 +1,168 @@ +name: 'Purview: Accounts' + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: 'Execute static validation' + required: false + default: true + deploymentValidation: + type: boolean + description: 'Execute deployment validation' + required: false + default: true + removeDeployment: + type: boolean + description: 'Remove deployed module' + required: false + default: true + prerelease: + type: boolean + description: 'Publish prerelease module' + required: false + default: false + push: + branches: + - main + paths: + - '.github/actions/templates/**' + - '.github/workflows/ms.purview.accounts.yml' + - 'modules/Microsoft.Purview/accounts/**' + - 'utilities/pipelines/**' + - '!utilities/pipelines/deploymentRemoval/**' + - '!*/**/readme.md' + +env: + variablesPath: 'settings.yml' + modulePath: 'modules/Microsoft.Purview/accounts' + workflowPath: '.github/workflows/ms.purview.accounts.yml' + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + ARM_SUBSCRIPTION_ID: '${{ secrets.ARM_SUBSCRIPTION_ID }}' + ARM_MGMTGROUP_ID: '${{ secrets.ARM_MGMTGROUP_ID }}' + ARM_TENANT_ID: '${{ secrets.ARM_TENANT_ID }}' + TOKEN_NAMEPREFIX: '${{ secrets.TOKEN_NAMEPREFIX }}' + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-20.04 + name: 'Initialize pipeline' + steps: + - name: 'Checkout' + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: 'Set input parameters to output variables' + id: get-workflow-param + uses: ./.github/actions/templates/getWorkflowInput + with: + workflowPath: '${{ env.workflowPath}}' + - name: 'Get parameter file paths' + id: get-module-test-file-paths + uses: ./.github/actions/templates/getModuleTestFiles + with: + modulePath: '${{ env.modulePath }}' + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + + ######################### + # Static validation # + ######################### + job_module_static_validation: + runs-on: ubuntu-20.04 + name: 'Static validation' + if: (fromJson(needs.job_initialize_pipeline.outputs.workflowInput)).staticValidation == 'true' + needs: + - job_initialize_pipeline + steps: + - name: 'Checkout' + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set environment variables + uses: ./.github/actions/templates/setEnvironmentVariables + with: + variablesPath: ${{ env.variablesPath }} + - name: 'Run tests' + uses: ./.github/actions/templates/validateModulePester + with: + modulePath: '${{ env.modulePath }}' + moduleTestFilePath: '${{ env.moduleTestFilePath }}' + + ############################# + # Deployment validation # + ############################# + job_module_deploy_validation: + runs-on: ubuntu-20.04 + name: 'Deploying' + if: | + !cancelled() && + (fromJson(needs.job_initialize_pipeline.outputs.workflowInput)).deploymentValidation == 'true' && + needs.job_module_static_validation.result != 'failure' + needs: + - job_initialize_pipeline + - job_module_static_validation + strategy: + fail-fast: false + matrix: + moduleTestFilePaths: ${{ fromJson(needs.job_initialize_pipeline.outputs.moduleTestFilePaths) }} + steps: + - name: 'Checkout' + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set environment variables + uses: ./.github/actions/templates/setEnvironmentVariables + with: + variablesPath: ${{ env.variablesPath }} + # ------------------- # + ## Deploy & Remove ## + # ------------------- # + - name: 'Using test file [${{ matrix.moduleTestFilePaths }}]' + uses: ./.github/actions/templates/validateModuleDeployment + with: + templateFilePath: '${{ env.modulePath }}/${{ matrix.moduleTestFilePaths }}' + location: '${{ env.location }}' + subscriptionId: '${{ secrets.ARM_SUBSCRIPTION_ID }}' + managementGroupId: '${{ secrets.ARM_MGMTGROUP_ID }}' + removeDeployment: '${{ (fromJson(needs.job_initialize_pipeline.outputs.workflowInput)).removeDeployment }}' + + ################## + # Publishing # + ################## + job_publish_module: + name: 'Publishing' + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || github.event.inputs.prerelease == 'true' + runs-on: ubuntu-20.04 + needs: + - job_module_deploy_validation + steps: + - name: 'Checkout' + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set environment variables + uses: ./.github/actions/templates/setEnvironmentVariables + with: + variablesPath: ${{ env.variablesPath }} + - name: 'Publishing' + uses: ./.github/actions/templates/publishModule + with: + templateFilePath: '${{ env.modulePath }}/deploy.bicep' + templateSpecsRGName: '${{ env.templateSpecsRGName }}' + templateSpecsRGLocation: '${{ env.templateSpecsRGLocation }}' + templateSpecsDescription: '${{ env.templateSpecsDescription }}' + templateSpecsDoPublish: '${{ env.templateSpecsDoPublish }}' + bicepRegistryName: '${{ env.bicepRegistryName }}' + bicepRegistryRGName: '${{ env.bicepRegistryRGName }}' + bicepRegistryRgLocation: '${{ env.bicepRegistryRgLocation }}' + bicepRegistryDoPublish: '${{ env.bicepRegistryDoPublish }}' + publishLatest: '${{ env.publishLatest }}' diff --git a/modules/Microsoft.Purview/accounts/.bicep/nested_roleAssignments.bicep b/modules/Microsoft.Purview/accounts/.bicep/nested_roleAssignments.bicep new file mode 100644 index 0000000000..0287728458 --- /dev/null +++ b/modules/Microsoft.Purview/accounts/.bicep/nested_roleAssignments.bicep @@ -0,0 +1,71 @@ +@sys.description('Required. The IDs of the principals to assign the role to.') +param principalIds array + +@sys.description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') +param roleDefinitionIdOrName string + +@sys.description('Required. The resource ID of the resource to apply the role assignment to.') +param resourceId string + +@sys.description('Optional. The principal type of the assigned principal ID.') +@allowed([ + 'ServicePrincipal' + 'Group' + 'User' + 'ForeignGroup' + 'Device' + '' +]) +param principalType string = '' + +@sys.description('Optional. The description of the role assignment.') +param description string = '' + +@sys.description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container".') +param condition string = '' + +@sys.description('Optional. Version of the condition.') +@allowed([ + '2.0' +]) +param conditionVersion string = '2.0' + +@sys.description('Optional. Id of the delegated managed identity resource.') +param delegatedManagedIdentityResourceId string = '' + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Log Analytics Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293') + 'Log Analytics Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893') + 'Managed Application Contributor Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '641177b8-a67a-45b9-a033-47bc880bb21e') + 'Managed Application Operator Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c7393b34-138c-406f-901b-d8cf2b17e6ae') + 'Managed Applications Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b9331d33-8a36-4f8c-b097-4f54124fdb44') + 'Monitoring Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa') + 'Monitoring Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Purview role 1 (Deprecated)': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a3c2885-9b38-4fd2-9d99-91af537c1347') + 'Purview role 2 (Deprecated)': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '200bba9e-f0c8-430f-892b-6f0794863803') + 'Purview role 3 (Deprecated)': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ff100721-1b9d-43d8-af52-42b69c1272db') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Resource Policy Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '36243c78-bf99-498c-9df9-86d9f8d28608') + 'Role Based Access Control Administrator (Preview)': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168') + 'User Access Administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9') +} + +resource purviewAccount 'Microsoft.Purview/accounts@2021-07-01' existing = { + name: last(split(resourceId, '/')) +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for principalId in principalIds: { + name: guid(purviewAccount.id, principalId, roleDefinitionIdOrName) + properties: { + description: description + roleDefinitionId: contains(builtInRoleNames, roleDefinitionIdOrName) ? builtInRoleNames[roleDefinitionIdOrName] : roleDefinitionIdOrName + principalId: principalId + principalType: !empty(principalType) ? any(principalType) : null + condition: !empty(condition) ? condition : null + conditionVersion: !empty(conditionVersion) && !empty(condition) ? conditionVersion : null + delegatedManagedIdentityResourceId: !empty(delegatedManagedIdentityResourceId) ? delegatedManagedIdentityResourceId : null + } + scope: purviewAccount +}] diff --git a/modules/Microsoft.Purview/accounts/.test/common/dependencies.bicep b/modules/Microsoft.Purview/accounts/.test/common/dependencies.bicep new file mode 100644 index 0000000000..0987da418b --- /dev/null +++ b/modules/Microsoft.Purview/accounts/.test/common/dependencies.bicep @@ -0,0 +1,73 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +var privateDNSZoneNames = [ + 'privatelink.purview.azure.com' + 'privatelink.purviewstudio.azure.com' + 'privatelink.blob.core.windows.net' + 'privatelink.queue.core.windows.net' + 'privatelink.servicebus.windows.net' +] + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2022-01-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: '10.0.0.0/24' + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@batchSize(1) +resource privateDNSZones 'Microsoft.Network/privateDnsZones@2020-06-01' = [for privateDNSZone in privateDNSZoneNames: { + name: privateDNSZone + location: 'global' +}] + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Private DNS Zone for Purview Account.') +output purviewAccountPrivateDNSResourceId string = privateDNSZones[0].id + +@description('The resource ID of the created Private DNS Zone for Purview Portal.') +output purviewPortalPrivateDNSResourceId string = privateDNSZones[1].id + +@description('The resource ID of the created Private DNS Zone for Storage Account Blob.') +output storageBlobPrivateDNSResourceId string = privateDNSZones[2].id + +@description('The resource ID of the created Private DNS Zone for Storage Account Queue.') +output storageQueuePrivateDNSResourceId string = privateDNSZones[3].id + +@description('The resource ID of the created Private DNS Zone for Event Hub Namespace.') +output eventHubPrivateDNSResourceId string = privateDNSZones[4].id diff --git a/modules/Microsoft.Purview/accounts/.test/common/deploy.test.bicep b/modules/Microsoft.Purview/accounts/.test/common/deploy.test.bicep new file mode 100644 index 0000000000..45c3bbdc3b --- /dev/null +++ b/modules/Microsoft.Purview/accounts/.test/common/deploy.test.bicep @@ -0,0 +1,148 @@ +targetScope = 'subscription' + +// ========== // +// Parameters // +// ========== // +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'ms.purview-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param location string = deployment().location + +@description('Tags') +param tags object = {} + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'pvacom' + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableDefaultTelemetry bool = false + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-<>-vnet-${serviceShort}' + managedIdentityName: 'dep-<>-msi-${serviceShort}' + } +} + +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../.shared/dependencyConstructs/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-diagnosticDependencies' + params: { + storageAccountName: 'dep<>diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-<>-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-<>-evh-${serviceShort}01' + eventHubNamespaceName: 'dep-<>-evhns-${serviceShort}01' + location: location + + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../deploy.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + name: '<>${serviceShort}001' + location: location + tags: tags + userAssignedIdentities: { + '${nestedDependencies.outputs.managedIdentityResourceId}': {} + } + managedResourceGroupName: '<>${serviceShort}001-managed-rg' + publicNetworkAccess: 'Disabled' + diagnosticLogsRetentionInDays: 7 + diagnosticStorageAccountId: diagnosticDependencies.outputs.storageAccountResourceId + diagnosticWorkspaceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + diagnosticEventHubAuthorizationRuleId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + diagnosticEventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalIds: [ + nestedDependencies.outputs.managedIdentityPrincipalId + ] + principalType: 'ServicePrincipal' + } + ] + accountPrivateEndpoints: [ + { + privateDnsZoneGroup: { + privateDNSResourceIds: [ + nestedDependencies.outputs.purviewAccountPrivateDNSResourceId + ] + } + service: 'account' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + portalPrivateEndpoints: [ + { + privateDnsZoneGroup: { + privateDNSResourceIds: [ + nestedDependencies.outputs.purviewPortalPrivateDNSResourceId + ] + } + service: 'portal' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + storageBlobPrivateEndpoints: [ + { + privateDnsZoneGroup: { + privateDNSResourceIds: [ + nestedDependencies.outputs.storageBlobPrivateDNSResourceId + ] + } + service: 'blob' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + storageQueuePrivateEndpoints: [ + { + privateDnsZoneGroup: { + privateDNSResourceIds: [ + nestedDependencies.outputs.storageQueuePrivateDNSResourceId + ] + } + service: 'queue' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + eventHubPrivateEndpoints: [ + { + privateDnsZoneGroup: { + privateDNSResourceIds: [ + nestedDependencies.outputs.eventHubPrivateDNSResourceId + ] + } + service: 'namespace' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + enableDefaultTelemetry: enableDefaultTelemetry + diagnosticLogCategoriesToEnable: [ 'allLogs' ] + diagnosticMetricsToEnable: [ 'AllMetrics' ] + lock: 'CanNotDelete' + } +} diff --git a/modules/Microsoft.Purview/accounts/.test/min/deploy.test.bicep b/modules/Microsoft.Purview/accounts/.test/min/deploy.test.bicep new file mode 100644 index 0000000000..fbc4ea6ccd --- /dev/null +++ b/modules/Microsoft.Purview/accounts/.test/min/deploy.test.bicep @@ -0,0 +1,42 @@ +targetScope = 'subscription' + +// ========== // +// Parameters // +// ========== // +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'ms.purview-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param location string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'pvamin' + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableDefaultTelemetry bool = true + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../deploy.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + name: '<>${serviceShort}001' + managedResourceGroupName: '<>${serviceShort}001-managed-rg' + enableDefaultTelemetry: enableDefaultTelemetry + } +} diff --git a/modules/Microsoft.Purview/accounts/deploy.bicep b/modules/Microsoft.Purview/accounts/deploy.bicep new file mode 100644 index 0000000000..56b162215c --- /dev/null +++ b/modules/Microsoft.Purview/accounts/deploy.bicep @@ -0,0 +1,336 @@ +@description('Required. Name of the Purview Account.') +@minLength(3) +@maxLength(63) +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +param tags object = {} + +@description('Optional. The ID(s) to assign to the resource.') +param userAssignedIdentities object = {} + +@description('Optional. The Managed Resource Group Name. A managed Storage Account, and an Event Hubs will be created in the selected subscription for catalog ingestion scenarios. Default is \'managed-rg-\'.') +param managedResourceGroupName string = 'managed-rg-${name}' + +@description('Optional. 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.') +@allowed([ + 'Enabled' + 'Disabled' + 'NotSpecified' +]) +param publicNetworkAccess string = 'NotSpecified' + +@description('Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely.') +@minValue(0) +@maxValue(365) +param diagnosticLogsRetentionInDays int = 365 + +@description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') +param diagnosticStorageAccountId string = '' + +@description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') +param diagnosticWorkspaceId string = '' + +@description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') +param diagnosticEventHubAuthorizationRuleId string = '' + +@description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') +param diagnosticEventHubName string = '' + +@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 = [] + +@description('Optional. Configuration details for Purview Account private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Make sure the service property is set to \'account\'.') +param accountPrivateEndpoints array = [] + +@description('Optional. Configuration details for Purview Portal private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Make sure the service property is set to \'portal\'.') +param portalPrivateEndpoints array = [] + +@description('Optional. Configuration details for Purview Managed Storage Account blob private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Make sure the service property is set to \'blob\'.') +param storageBlobPrivateEndpoints array = [] + +@description('Optional. Configuration details for Purview Managed Storage Account queue private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Make sure the service property is set to \'queue\'.') +param storageQueuePrivateEndpoints array = [] + +@description('Optional. Configuration details for Purview Managed Event Hub namespace private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Make sure the service property is set to \'namespace\'.') +param eventHubPrivateEndpoints array = [] + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableDefaultTelemetry bool = true + +@description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource.') +@allowed([ + 'allLogs' + 'ScanStatus' + 'DataSensitivity' + 'PurviewAccountAuditEvents' +]) +param diagnosticLogCategoriesToEnable array = [ + 'allLogs' +] + +@description('Optional. The name of metrics that will be streamed.') +@allowed([ + 'AllMetrics' +]) +param diagnosticMetricsToEnable array = [ + 'AllMetrics' +] + +@description('Optional. The name of the diagnostic setting, if deployed.') +param diagnosticSettingsName string = '${name}-diagnosticSettings' + +@allowed([ + '' + 'CanNotDelete' + 'ReadOnly' +]) +@description('Optional. Specify the type of lock.') +param lock string = '' + +// =========== // +// Variables // +// =========== // + +var diagnosticsLogsSpecified = [for category in filter(diagnosticLogCategoriesToEnable, item => item != 'allLogs'): { + category: category + enabled: true + retentionPolicy: { + enabled: true + days: diagnosticLogsRetentionInDays + } +}] + +var diagnosticsLogs = contains(diagnosticLogCategoriesToEnable, 'allLogs') ? [ + { + categoryGroup: 'allLogs' + enabled: true + retentionPolicy: { + enabled: true + days: diagnosticLogsRetentionInDays + } + } +] : diagnosticsLogsSpecified + +var diagnosticsMetrics = [for metric in diagnosticMetricsToEnable: { + category: metric + timeGrain: null + enabled: true + retentionPolicy: { + enabled: true + days: diagnosticLogsRetentionInDays + } +}] + +var identityType = !empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned' + +var identity = identityType != 'None' ? { + type: identityType + userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +} : null + +var enableReferencedModulesTelemetry = false + +resource defaultTelemetry 'Microsoft.Resources/deployments@2021-04-01' = if (enableDefaultTelemetry) { + name: 'pid-47ed15a6-730a-4827-bcb4-0fd963ffbd82-${uniqueString(deployment().name, location)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } +} + +resource account 'Microsoft.Purview/accounts@2021-07-01' = { + name: name + location: location + tags: tags + identity: any(identity) + properties: { + cloudConnectors: {} + managedResourceGroupName: managedResourceGroupName + publicNetworkAccess: publicNetworkAccess + } +} + +resource purview_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock)) { + name: '${account.name}-${lock}-lock' + properties: { + level: any(lock) + notes: lock == 'CanNotDelete' ? 'Cannot delete resource or child resources.' : 'Cannot modify the resource or child resources.' + } + scope: account +} + +resource purview_diagnosticSettings 'Microsoft.Insights/diagnosticsettings@2021-05-01-preview' = if ((!empty(diagnosticStorageAccountId)) || (!empty(diagnosticWorkspaceId)) || (!empty(diagnosticEventHubAuthorizationRuleId)) || (!empty(diagnosticEventHubName))) { + name: diagnosticSettingsName + properties: { + storageAccountId: !empty(diagnosticStorageAccountId) ? diagnosticStorageAccountId : null + workspaceId: !empty(diagnosticWorkspaceId) ? diagnosticWorkspaceId : null + eventHubAuthorizationRuleId: !empty(diagnosticEventHubAuthorizationRuleId) ? diagnosticEventHubAuthorizationRuleId : null + eventHubName: !empty(diagnosticEventHubName) ? diagnosticEventHubName : null + metrics: diagnosticsMetrics + logs: diagnosticsLogs + } + scope: account +} + +module account_privateEndpoints '../../Microsoft.Network/privateEndpoints/deploy.bicep' = [for (privateEndpoint, index) in accountPrivateEndpoints: { + name: '${uniqueString(deployment().name, location)}-Account-PrivateEndpoint-${index}' + params: { + groupIds: [ + privateEndpoint.service + ] + name: contains(privateEndpoint, 'name') ? privateEndpoint.name : 'pe-${last(split(account.id, '/'))}-${privateEndpoint.service}-${index}' + serviceResourceId: account.id + subnetResourceId: privateEndpoint.subnetResourceId + enableDefaultTelemetry: enableReferencedModulesTelemetry + location: reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location + lock: contains(privateEndpoint, 'lock') ? privateEndpoint.lock : lock + privateDnsZoneGroup: contains(privateEndpoint, 'privateDnsZoneGroup') ? privateEndpoint.privateDnsZoneGroup : {} + roleAssignments: contains(privateEndpoint, 'roleAssignments') ? privateEndpoint.roleAssignments : [] + tags: contains(privateEndpoint, 'tags') ? privateEndpoint.tags : {} + manualPrivateLinkServiceConnections: contains(privateEndpoint, 'manualPrivateLinkServiceConnections') ? privateEndpoint.manualPrivateLinkServiceConnections : [] + customDnsConfigs: contains(privateEndpoint, 'customDnsConfigs') ? privateEndpoint.customDnsConfigs : [] + ipConfigurations: contains(privateEndpoint, 'ipConfigurations') ? privateEndpoint.ipConfigurations : [] + applicationSecurityGroups: contains(privateEndpoint, 'applicationSecurityGroups') ? privateEndpoint.applicationSecurityGroups : [] + customNetworkInterfaceName: contains(privateEndpoint, 'customNetworkInterfaceName') ? privateEndpoint.customNetworkInterfaceName : '' + } +}] + +module portal_privateEndpoints '../../Microsoft.Network/privateEndpoints/deploy.bicep' = [for (privateEndpoint, index) in portalPrivateEndpoints: { + name: '${uniqueString(deployment().name, location)}-Portal-PrivateEndpoint-${index}' + params: { + groupIds: [ + privateEndpoint.service + ] + name: contains(privateEndpoint, 'name') ? privateEndpoint.name : 'pe-${last(split(account.id, '/'))}-${privateEndpoint.service}-${index}' + serviceResourceId: account.id + subnetResourceId: privateEndpoint.subnetResourceId + enableDefaultTelemetry: enableReferencedModulesTelemetry + location: reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location + lock: contains(privateEndpoint, 'lock') ? privateEndpoint.lock : lock + privateDnsZoneGroup: contains(privateEndpoint, 'privateDnsZoneGroup') ? privateEndpoint.privateDnsZoneGroup : {} + roleAssignments: contains(privateEndpoint, 'roleAssignments') ? privateEndpoint.roleAssignments : [] + tags: contains(privateEndpoint, 'tags') ? privateEndpoint.tags : {} + manualPrivateLinkServiceConnections: contains(privateEndpoint, 'manualPrivateLinkServiceConnections') ? privateEndpoint.manualPrivateLinkServiceConnections : [] + customDnsConfigs: contains(privateEndpoint, 'customDnsConfigs') ? privateEndpoint.customDnsConfigs : [] + ipConfigurations: contains(privateEndpoint, 'ipConfigurations') ? privateEndpoint.ipConfigurations : [] + applicationSecurityGroups: contains(privateEndpoint, 'applicationSecurityGroups') ? privateEndpoint.applicationSecurityGroups : [] + customNetworkInterfaceName: contains(privateEndpoint, 'customNetworkInterfaceName') ? privateEndpoint.customNetworkInterfaceName : '' + } +}] + +module blob_privateEndpoints '../../Microsoft.Network/privateEndpoints/deploy.bicep' = [for (privateEndpoint, index) in storageBlobPrivateEndpoints: { + name: '${uniqueString(deployment().name, location)}-Storage-Blob-PrivateEndpoint-${index}' + params: { + groupIds: [ + privateEndpoint.service + ] + name: contains(privateEndpoint, 'name') ? privateEndpoint.name : 'pe-${last(split(account.id, '/'))}-${privateEndpoint.service}-${index}' + serviceResourceId: account.properties.managedResources.storageAccount + subnetResourceId: privateEndpoint.subnetResourceId + enableDefaultTelemetry: enableReferencedModulesTelemetry + location: reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location + lock: contains(privateEndpoint, 'lock') ? privateEndpoint.lock : lock + privateDnsZoneGroup: contains(privateEndpoint, 'privateDnsZoneGroup') ? privateEndpoint.privateDnsZoneGroup : {} + roleAssignments: contains(privateEndpoint, 'roleAssignments') ? privateEndpoint.roleAssignments : [] + tags: contains(privateEndpoint, 'tags') ? privateEndpoint.tags : {} + manualPrivateLinkServiceConnections: contains(privateEndpoint, 'manualPrivateLinkServiceConnections') ? privateEndpoint.manualPrivateLinkServiceConnections : [] + customDnsConfigs: contains(privateEndpoint, 'customDnsConfigs') ? privateEndpoint.customDnsConfigs : [] + ipConfigurations: contains(privateEndpoint, 'ipConfigurations') ? privateEndpoint.ipConfigurations : [] + applicationSecurityGroups: contains(privateEndpoint, 'applicationSecurityGroups') ? privateEndpoint.applicationSecurityGroups : [] + customNetworkInterfaceName: contains(privateEndpoint, 'customNetworkInterfaceName') ? privateEndpoint.customNetworkInterfaceName : '' + } +}] + +module queue_privateEndpoints '../../Microsoft.Network/privateEndpoints/deploy.bicep' = [for (privateEndpoint, index) in storageQueuePrivateEndpoints: { + name: '${uniqueString(deployment().name, location)}-Storage-Queue-PrivateEndpoint-${index}' + params: { + groupIds: [ + privateEndpoint.service + ] + name: contains(privateEndpoint, 'name') ? privateEndpoint.name : 'pe-${last(split(account.id, '/'))}-${privateEndpoint.service}-${index}' + serviceResourceId: account.properties.managedResources.storageAccount + subnetResourceId: privateEndpoint.subnetResourceId + enableDefaultTelemetry: enableReferencedModulesTelemetry + location: reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location + lock: contains(privateEndpoint, 'lock') ? privateEndpoint.lock : lock + privateDnsZoneGroup: contains(privateEndpoint, 'privateDnsZoneGroup') ? privateEndpoint.privateDnsZoneGroup : {} + roleAssignments: contains(privateEndpoint, 'roleAssignments') ? privateEndpoint.roleAssignments : [] + tags: contains(privateEndpoint, 'tags') ? privateEndpoint.tags : {} + manualPrivateLinkServiceConnections: contains(privateEndpoint, 'manualPrivateLinkServiceConnections') ? privateEndpoint.manualPrivateLinkServiceConnections : [] + customDnsConfigs: contains(privateEndpoint, 'customDnsConfigs') ? privateEndpoint.customDnsConfigs : [] + ipConfigurations: contains(privateEndpoint, 'ipConfigurations') ? privateEndpoint.ipConfigurations : [] + applicationSecurityGroups: contains(privateEndpoint, 'applicationSecurityGroups') ? privateEndpoint.applicationSecurityGroups : [] + customNetworkInterfaceName: contains(privateEndpoint, 'customNetworkInterfaceName') ? privateEndpoint.customNetworkInterfaceName : '' + } +}] + +module eventHub_privateEndpoints '../../Microsoft.Network/privateEndpoints/deploy.bicep' = [for (privateEndpoint, index) in eventHubPrivateEndpoints: { + name: '${uniqueString(deployment().name, location)}-Eventhub-Namespace-PrivateEndpoint-${index}' + params: { + groupIds: [ + privateEndpoint.service + ] + name: contains(privateEndpoint, 'name') ? privateEndpoint.name : 'pe-${last(split(account.id, '/'))}-${privateEndpoint.service}-${index}' + serviceResourceId: account.properties.managedResources.eventHubNamespace + subnetResourceId: privateEndpoint.subnetResourceId + enableDefaultTelemetry: enableReferencedModulesTelemetry + location: reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location + lock: contains(privateEndpoint, 'lock') ? privateEndpoint.lock : lock + privateDnsZoneGroup: contains(privateEndpoint, 'privateDnsZoneGroup') ? privateEndpoint.privateDnsZoneGroup : {} + roleAssignments: contains(privateEndpoint, 'roleAssignments') ? privateEndpoint.roleAssignments : [] + tags: contains(privateEndpoint, 'tags') ? privateEndpoint.tags : {} + manualPrivateLinkServiceConnections: contains(privateEndpoint, 'manualPrivateLinkServiceConnections') ? privateEndpoint.manualPrivateLinkServiceConnections : [] + customDnsConfigs: contains(privateEndpoint, 'customDnsConfigs') ? privateEndpoint.customDnsConfigs : [] + ipConfigurations: contains(privateEndpoint, 'ipConfigurations') ? privateEndpoint.ipConfigurations : [] + applicationSecurityGroups: contains(privateEndpoint, 'applicationSecurityGroups') ? privateEndpoint.applicationSecurityGroups : [] + customNetworkInterfaceName: contains(privateEndpoint, 'customNetworkInterfaceName') ? privateEndpoint.customNetworkInterfaceName : '' + } +}] + +module purview_roleAssignments '.bicep/nested_roleAssignments.bicep' = [for (roleAssignment, index) in roleAssignments: { + name: '${uniqueString(deployment().name, location)}-Account-Rbac-${index}' + params: { + description: contains(roleAssignment, 'description') ? roleAssignment.description : '' + principalIds: roleAssignment.principalIds + principalType: contains(roleAssignment, 'principalType') ? roleAssignment.principalType : '' + roleDefinitionIdOrName: roleAssignment.roleDefinitionIdOrName + condition: contains(roleAssignment, 'condition') ? roleAssignment.condition : '' + delegatedManagedIdentityResourceId: contains(roleAssignment, 'delegatedManagedIdentityResourceId') ? roleAssignment.delegatedManagedIdentityResourceId : '' + resourceId: account.id + } +}] + +@description('The name of the Purview Account.') +output name string = account.name + +@description('The resource group the Purview Account was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the Purview Account.') +output resourceId string = account.id + +@description('The location the resource was deployed into.') +output location string = account.location + +@description('The name of the managed resource group.') +output managedResourceGroupName string = account.properties.managedResourceGroupName + +@description('The resource ID of the managed resource group.') +output managedResourceGroupId string = account.properties.managedResources.resourceGroup + +@description('The resource ID of the managed storage account.') +output managedStorageAccountId string = account.properties.managedResources.storageAccount + +@description('The resource ID of the managed Event Hub Namespace.') +output managedEventHubId string = account.properties.managedResources.eventHubNamespace + +@description('The principal ID of the system assigned identity.') +output systemAssignedPrincipalId string = account.identity.principalId diff --git a/modules/Microsoft.Purview/accounts/readme.md b/modules/Microsoft.Purview/accounts/readme.md new file mode 100644 index 0000000000..5d03a1292a --- /dev/null +++ b/modules/Microsoft.Purview/accounts/readme.md @@ -0,0 +1,517 @@ +# Purview Accounts `[Microsoft.Purview/accounts]` + +This module deploys Purview Accounts. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Deployment examples](#Deployment-examples) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/locks` | [2020-05-01](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/privateEndpoints` | [2022-05-01](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-05-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2022-05-01](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-05-01/privateEndpoints/privateDnsZoneGroups) | +| `Microsoft.Purview/accounts` | [2021-07-01](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Purview/2021-07-01/accounts) | + +## Parameters + +**Required parameters** + +| Parameter Name | Type | Description | +| :-- | :-- | :-- | +| `name` | string | Name of the Purview Account. | + +**Optional parameters** + +| Parameter Name | Type | Default Value | Allowed Values | Description | +| :-- | :-- | :-- | :-- | :-- | +| `accountPrivateEndpoints` | array | `[]` | | Configuration details for Purview Account private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Make sure the service property is set to 'account'. | +| `diagnosticEventHubAuthorizationRuleId` | string | `''` | | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| `diagnosticEventHubName` | string | `''` | | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| `diagnosticLogCategoriesToEnable` | array | `[allLogs]` | `[allLogs, DataSensitivity, PurviewAccountAuditEvents, ScanStatus]` | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. | +| `diagnosticLogsRetentionInDays` | int | `365` | | Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely. | +| `diagnosticMetricsToEnable` | array | `[AllMetrics]` | `[AllMetrics]` | The name of metrics that will be streamed. | +| `diagnosticSettingsName` | string | `[format('{0}-diagnosticSettings', parameters('name'))]` | | The name of the diagnostic setting, if deployed. | +| `diagnosticStorageAccountId` | string | `''` | | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| `diagnosticWorkspaceId` | string | `''` | | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| `enableDefaultTelemetry` | bool | `True` | | Enable telemetry via a Globally Unique Identifier (GUID). | +| `eventHubPrivateEndpoints` | array | `[]` | | Configuration details for Purview Managed Event Hub namespace private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Make sure the service property is set to 'namespace'. | +| `location` | string | `[resourceGroup().location]` | | Location for all resources. | +| `lock` | string | `''` | `['', CanNotDelete, ReadOnly]` | Specify the type of lock. | +| `managedResourceGroupName` | string | `[format('managed-rg-{0}', parameters('name'))]` | | The Managed Resource Group Name. A managed Storage Account, and an Event Hubs will be created in the selected subscription for catalog ingestion scenarios. Default is 'managed-rg-'. | +| `portalPrivateEndpoints` | array | `[]` | | Configuration details for Purview Portal private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Make sure the service property is set to 'portal'. | +| `publicNetworkAccess` | string | `'NotSpecified'` | `[Disabled, Enabled, NotSpecified]` | 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. | +| `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'. | +| `storageBlobPrivateEndpoints` | array | `[]` | | Configuration details for Purview Managed Storage Account blob private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Make sure the service property is set to 'blob'. | +| `storageQueuePrivateEndpoints` | array | `[]` | | Configuration details for Purview Managed Storage Account queue private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Make sure the service property is set to 'queue'. | +| `tags` | object | `{object}` | | Tags of the resource. | +| `userAssignedIdentities` | object | `{object}` | | The ID(s) to assign to the resource. | + + +### Parameter Usage: `roleAssignments` + +Create a role assignment for the given resource. If you want to assign a service principal / managed identity that is created in the same deployment, make sure to also specify the `'principalType'` parameter and set it to `'ServicePrincipal'`. This will ensure the role assignment waits for the principal's propagation in Azure. + +
+ +Parameter JSON format + +```json +"roleAssignments": { + "value": [ + { + "roleDefinitionIdOrName": "Reader", + "description": "Reader Role Assignment", + "principalIds": [ + "12345678-1234-1234-1234-123456789012", // object 1 + "78945612-1234-1234-1234-123456789012" // object 2 + ] + }, + { + "roleDefinitionIdOrName": "/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11", + "principalIds": [ + "12345678-1234-1234-1234-123456789012" // object 1 + ], + "principalType": "ServicePrincipal" + } + ] +} +``` + +
+ +
+ +Bicep format + +```bicep +roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + description: 'Reader Role Assignment' + principalIds: [ + '12345678-1234-1234-1234-123456789012' // object 1 + '78945612-1234-1234-1234-123456789012' // object 2 + ] + } + { + roleDefinitionIdOrName: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11' + principalIds: [ + '12345678-1234-1234-1234-123456789012' // object 1 + ] + principalType: 'ServicePrincipal' + } +] +``` + +
+

+ +### Parameter Usage: `tags` + +Tag names and tag values can be provided as needed. A tag can be left without a value. + +

+ +Parameter JSON format + +```json +"tags": { + "value": { + "Environment": "Non-Prod", + "Contact": "test.user@testcompany.com", + "PurchaseOrder": "1234", + "CostCenter": "7890", + "ServiceName": "DeploymentValidation", + "Role": "DeploymentValidation" + } +} +``` + +
+ +
+ +Bicep format + +```bicep +tags: { + Environment: 'Non-Prod' + Contact: 'test.user@testcompany.com' + PurchaseOrder: '1234' + CostCenter: '7890' + ServiceName: 'DeploymentValidation' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Parameter Usage: `userAssignedIdentities` + +You can specify multiple user assigned identities to a resource by providing additional resource IDs using the following format: + +

+ +Parameter JSON format + +```json +"userAssignedIdentities": { + "value": { + "/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-sxx-az-msi-x-001": {}, + "/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-sxx-az-msi-x-002": {} + } +} +``` + +
+ +
+ +Bicep format + +```bicep +userAssignedIdentities: { + '/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-sxx-az-msi-x-001': {} + '/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-sxx-az-msi-x-002': {} +} +``` + +
+

+ +## Outputs + +| Output Name | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `managedEventHubId` | string | The resource ID of the managed Event Hub Namespace. | +| `managedResourceGroupId` | string | The resource ID of the managed resource group. | +| `managedResourceGroupName` | string | The name of the managed resource group. | +| `managedStorageAccountId` | string | The resource ID of the managed storage account. | +| `name` | string | The name of the Purview Account. | +| `resourceGroupName` | string | The resource group the Purview Account was deployed into. | +| `resourceId` | string | The resource ID of the Purview Account. | +| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other CARML modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `Microsoft.Network/privateEndpoints` | Local reference | + +## Deployment examples + +The following module usage examples are retrieved from the content of the files hosted in the module's `.test` folder. + >**Note**: The name of each example is based on the name of the file from which it is taken. + + >**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +

Example 1: Common

+ +
+ +via Bicep module + +```bicep +module accounts './Microsoft.Purview/accounts/deploy.bicep' = { + name: '${uniqueString(deployment().name)}-test-pvacom' + params: { + // Required parameters + name: '<>pvacom001' + // Non-required parameters + accountPrivateEndpoints: [ + { + privateDnsZoneGroup: { + privateDNSResourceIds: [ + '' + ] + } + service: 'account' + subnetResourceId: '' + } + ] + diagnosticEventHubAuthorizationRuleId: '' + diagnosticEventHubName: '' + diagnosticLogCategoriesToEnable: [ + 'allLogs' + ] + diagnosticLogsRetentionInDays: 7 + diagnosticMetricsToEnable: [ + 'AllMetrics' + ] + diagnosticStorageAccountId: '' + diagnosticWorkspaceId: '' + enableDefaultTelemetry: '' + eventHubPrivateEndpoints: [ + { + privateDnsZoneGroup: { + privateDNSResourceIds: [ + '' + ] + } + service: 'namespace' + subnetResourceId: '' + } + ] + location: '' + lock: 'CanNotDelete' + managedResourceGroupName: '<>pvacom001-managed-rg' + portalPrivateEndpoints: [ + { + privateDnsZoneGroup: { + privateDNSResourceIds: [ + '' + ] + } + service: 'portal' + subnetResourceId: '' + } + ] + publicNetworkAccess: 'Disabled' + roleAssignments: [ + { + principalIds: [ + '' + ] + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + storageBlobPrivateEndpoints: [ + { + privateDnsZoneGroup: { + privateDNSResourceIds: [ + '' + ] + } + service: 'blob' + subnetResourceId: '' + } + ] + storageQueuePrivateEndpoints: [ + { + privateDnsZoneGroup: { + privateDNSResourceIds: [ + '' + ] + } + service: 'queue' + subnetResourceId: '' + } + ] + tags: '' + userAssignedIdentities: { + '': {} + } + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "<>pvacom001" + }, + // Non-required parameters + "accountPrivateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDNSResourceIds": [ + "" + ] + }, + "service": "account", + "subnetResourceId": "" + } + ] + }, + "diagnosticEventHubAuthorizationRuleId": { + "value": "" + }, + "diagnosticEventHubName": { + "value": "" + }, + "diagnosticLogCategoriesToEnable": { + "value": [ + "allLogs" + ] + }, + "diagnosticLogsRetentionInDays": { + "value": 7 + }, + "diagnosticMetricsToEnable": { + "value": [ + "AllMetrics" + ] + }, + "diagnosticStorageAccountId": { + "value": "" + }, + "diagnosticWorkspaceId": { + "value": "" + }, + "enableDefaultTelemetry": { + "value": "" + }, + "eventHubPrivateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDNSResourceIds": [ + "" + ] + }, + "service": "namespace", + "subnetResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": "CanNotDelete" + }, + "managedResourceGroupName": { + "value": "<>pvacom001-managed-rg" + }, + "portalPrivateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDNSResourceIds": [ + "" + ] + }, + "service": "portal", + "subnetResourceId": "" + } + ] + }, + "publicNetworkAccess": { + "value": "Disabled" + }, + "roleAssignments": { + "value": [ + { + "principalIds": [ + "" + ], + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ] + }, + "storageBlobPrivateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDNSResourceIds": [ + "" + ] + }, + "service": "blob", + "subnetResourceId": "" + } + ] + }, + "storageQueuePrivateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDNSResourceIds": [ + "" + ] + }, + "service": "queue", + "subnetResourceId": "" + } + ] + }, + "tags": { + "value": "" + }, + "userAssignedIdentities": { + "value": { + "": {} + } + } + } +} +``` + +
+

+ +

Example 2: Min

+ +
+ +via Bicep module + +```bicep +module accounts './Microsoft.Purview/accounts/deploy.bicep' = { + name: '${uniqueString(deployment().name)}-test-pvamin' + params: { + // Required parameters + name: '<>pvamin001' + // Non-required parameters + enableDefaultTelemetry: '' + managedResourceGroupName: '<>pvamin001-managed-rg' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "<>pvamin001" + }, + // Non-required parameters + "enableDefaultTelemetry": { + "value": "" + }, + "managedResourceGroupName": { + "value": "<>pvamin001-managed-rg" + } + } +} +``` + +
+

diff --git a/modules/Microsoft.Purview/accounts/version.json b/modules/Microsoft.Purview/accounts/version.json new file mode 100644 index 0000000000..41f66cc990 --- /dev/null +++ b/modules/Microsoft.Purview/accounts/version.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", + "version": "0.1" +}