From 73e6b969331e752ecfc9a1d8c414b872998f9c22 Mon Sep 17 00:00:00 2001 From: Kris Baranek Date: Fri, 24 Nov 2023 15:24:46 +0100 Subject: [PATCH 01/22] feat: New module `avm/res/db-for-postgre-sql/flexible-server` (#664) ## Description New Module `avm/res/db-for-postgre-sql/flexible-server`, migrated from CARML. ## Adding a new module - [x] A proposal has been submitted and approved. - [ ] I have included "Closes #{module_proposal_issue_number}" in the PR description. - [ ] I have run `brm validate` locally to verify the module files. - [x] I have run deployment tests locally to ensure the module is deployable. ## Pipeline references | Pipeline | | - | | [![avm.res.db-for-postgre-sql.flexible-server](https://github.com/krbar/bicep-registry-modules/actions/workflows/avm.res.db-for-postgre-sql.flexible-server.yml/badge.svg?branch=users%2Fkrbar%2FpostgreModule)](https://github.com/krbar/bicep-registry-modules/actions/workflows/avm.res.db-for-postgre-sql.flexible-server.yml)
**Note**: due to region limitation for the test subscriptions which is not allowed to deploy this resource in the region `West Europe`, the test have been performed in `North Europe`. The last commit (changing the region back to `West Europe`) was not included in the test. | --------- Co-authored-by: Alexander Sehr --- .github/CODEOWNERS | 2 +- ...res.db-for-postgre-sql.flexible-server.yml | 81 + .../flexible-server/README.md | 1341 +++++++++++++++++ .../flexible-server/administrator/README.md | 91 ++ .../flexible-server/administrator/main.bicep | 47 + .../flexible-server/administrator/main.json | 88 ++ .../flexible-server/configuration/README.md | 76 + .../flexible-server/configuration/main.bicep | 37 + .../flexible-server/configuration/main.json | 76 + .../flexible-server/database/README.md | 76 + .../flexible-server/database/main.bicep | 37 + .../flexible-server/database/main.json | 76 + .../flexible-server/firewall-rule/README.md | 69 + .../flexible-server/firewall-rule/main.bicep | 37 + .../flexible-server/firewall-rule/main.json | 74 + .../flexible-server/main.bicep | 455 ++++++ .../flexible-server/main.json | 1168 ++++++++++++++ .../tests/e2e/defaults/main.test.bicep | 54 + .../tests/e2e/encr/dependencies.bicep | 58 + .../tests/e2e/encr/main.test.bicep | 83 + .../tests/e2e/private/dependencies.bicep | 68 + .../tests/e2e/private/main.test.bicep | 122 ++ .../tests/e2e/public/dependencies.bicep | 19 + .../tests/e2e/public/main.test.bicep | 137 ++ .../tests/e2e/waf-aligned/dependencies.bicep | 71 + .../tests/e2e/waf-aligned/main.test.bicep | 119 ++ .../flexible-server/version.json | 7 + 27 files changed, 4568 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/avm.res.db-for-postgre-sql.flexible-server.yml create mode 100644 avm/res/db-for-postgre-sql/flexible-server/README.md create mode 100644 avm/res/db-for-postgre-sql/flexible-server/administrator/README.md create mode 100644 avm/res/db-for-postgre-sql/flexible-server/administrator/main.bicep create mode 100644 avm/res/db-for-postgre-sql/flexible-server/administrator/main.json create mode 100644 avm/res/db-for-postgre-sql/flexible-server/configuration/README.md create mode 100644 avm/res/db-for-postgre-sql/flexible-server/configuration/main.bicep create mode 100644 avm/res/db-for-postgre-sql/flexible-server/configuration/main.json create mode 100644 avm/res/db-for-postgre-sql/flexible-server/database/README.md create mode 100644 avm/res/db-for-postgre-sql/flexible-server/database/main.bicep create mode 100644 avm/res/db-for-postgre-sql/flexible-server/database/main.json create mode 100644 avm/res/db-for-postgre-sql/flexible-server/firewall-rule/README.md create mode 100644 avm/res/db-for-postgre-sql/flexible-server/firewall-rule/main.bicep create mode 100644 avm/res/db-for-postgre-sql/flexible-server/firewall-rule/main.json create mode 100644 avm/res/db-for-postgre-sql/flexible-server/main.bicep create mode 100644 avm/res/db-for-postgre-sql/flexible-server/main.json create mode 100644 avm/res/db-for-postgre-sql/flexible-server/tests/e2e/defaults/main.test.bicep create mode 100644 avm/res/db-for-postgre-sql/flexible-server/tests/e2e/encr/dependencies.bicep create mode 100644 avm/res/db-for-postgre-sql/flexible-server/tests/e2e/encr/main.test.bicep create mode 100644 avm/res/db-for-postgre-sql/flexible-server/tests/e2e/private/dependencies.bicep create mode 100644 avm/res/db-for-postgre-sql/flexible-server/tests/e2e/private/main.test.bicep create mode 100644 avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/dependencies.bicep create mode 100644 avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/main.test.bicep create mode 100644 avm/res/db-for-postgre-sql/flexible-server/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/res/db-for-postgre-sql/flexible-server/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/res/db-for-postgre-sql/flexible-server/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 24b1975eab..6282e877fd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -39,7 +39,7 @@ #/avm/res/data-factory/factory/ @Azure/avm-res-datafactory-factory-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/data-protection/backup-vault/ @Azure/avm-res-dataprotection-backupvault-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/db-for-my-sql/flexible-server/ @Azure/avm-res-dbformysql-flexibleserver-module-owners-bicep @Azure/avm-core-team-technical-bicep -#/avm/res/db-for-postgre-sql/flexible-server/ @Azure/avm-res-dbforpostgresql-flexibleserver-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/res/db-for-postgre-sql/flexible-server/ @Azure/avm-res-dbforpostgresql-flexibleserver-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/desktop-virtualization/application-group/ @Azure/avm-res-desktopvirtualization-applicationgroup-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/desktop-virtualization/host-pool/ @Azure/avm-res-desktopvirtualization-hostpool-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/desktop-virtualization/scaling-plan/ @Azure/avm-res-desktopvirtualization-scalingplan-module-owners-bicep @Azure/avm-core-team-technical-bicep diff --git a/.github/workflows/avm.res.db-for-postgre-sql.flexible-server.yml b/.github/workflows/avm.res.db-for-postgre-sql.flexible-server.yml new file mode 100644 index 0000000000..a2fee2b4e0 --- /dev/null +++ b/.github/workflows/avm.res.db-for-postgre-sql.flexible-server.yml @@ -0,0 +1,81 @@ +name: "avm.res.db-for-postgre-sql.flexible-server" + +on: + schedule: + - cron: "0 12 1/15 * *" # Bi-Weekly Test (on 1st & 15th of month) + 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 + + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.db-for-postgre-sql.flexible-server.yml" + - "avm/res/db-for-postgre-sql/flexible-server/**" + - "avm/utilities/pipelines/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/db-for-postgre-sql/flexible-server" + workflowPath: ".github/workflows/avm.res.db-for-postgre-sql.flexible-server.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-20.04 + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get parameter file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Module" + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/res/db-for-postgre-sql/flexible-server/README.md b/avm/res/db-for-postgre-sql/flexible-server/README.md new file mode 100644 index 0000000000..4b1ab8afb8 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/README.md @@ -0,0 +1,1341 @@ +# DBforPostgreSQL Flexible Servers `[Microsoft.DBforPostgreSQL/flexibleServers]` + +This module deploys a DBforPostgreSQL Flexible Server. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| 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/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.DBforPostgreSQL/flexibleServers` | [2022-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforPostgreSQL/2022-12-01/flexibleServers) | +| `Microsoft.DBforPostgreSQL/flexibleServers/administrators` | [2022-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforPostgreSQL/2022-12-01/flexibleServers/administrators) | +| `Microsoft.DBforPostgreSQL/flexibleServers/configurations` | [2022-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforPostgreSQL/2022-12-01/flexibleServers/configurations) | +| `Microsoft.DBforPostgreSQL/flexibleServers/databases` | [2022-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforPostgreSQL/2022-12-01/flexibleServers/databases) | +| `Microsoft.DBforPostgreSQL/flexibleServers/firewallRules` | [2022-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforPostgreSQL/2022-12-01/flexibleServers/firewallRules) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/db-for-postgre-sql/flexible-server:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using Customer-Managed-Keys with User-Assigned identity](#example-2-using-customer-managed-keys-with-user-assigned-identity) +- [Private access](#example-3-private-access) +- [Public access](#example-4-public-access) +- [WAF-aligned](#example-5-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +
+ +via Bicep module + +```bicep +module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:' = { + name: '${uniqueString(deployment().name, location)}-test-dfpsfsmin' + params: { + // Required parameters + name: 'dfpsfsmin001' + skuName: 'Standard_B2s' + tier: 'Burstable' + // Non-required parameters + administratorLogin: 'adminUserName' + administratorLoginPassword: '' + location: '' + } +} +``` + +
+

+ +

+ +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": "dfpsfsmin001" + }, + "skuName": { + "value": "Standard_B2s" + }, + "tier": { + "value": "Burstable" + }, + // Non-required parameters + "administratorLogin": { + "value": "adminUserName" + }, + "administratorLoginPassword": { + "value": "" + }, + "location": { + "value": "" + } + } +} +``` + +
+

+ +### Example 2: _Using Customer-Managed-Keys with User-Assigned identity_ + +This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret. + + +

+ +via Bicep module + +```bicep +module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:' = { + name: '${uniqueString(deployment().name, location)}-test-dfpsfse' + params: { + // Required parameters + name: 'dfpsfse001' + skuName: 'Standard_D2s_v3' + tier: 'GeneralPurpose' + // Non-required parameters + administratorLogin: 'adminUserName' + administratorLoginPassword: '' + customerManagedKey: { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' + } + databases: [ + { + name: 'testdb1' + } + ] + location: '' + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + } +} +``` + +
+

+ +

+ +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": "dfpsfse001" + }, + "skuName": { + "value": "Standard_D2s_v3" + }, + "tier": { + "value": "GeneralPurpose" + }, + // Non-required parameters + "administratorLogin": { + "value": "adminUserName" + }, + "administratorLoginPassword": { + "value": "" + }, + "customerManagedKey": { + "value": { + "keyName": "", + "keyVaultResourceId": "", + "userAssignedIdentityResourceId": "" + } + }, + "databases": { + "value": [ + { + "name": "testdb1" + } + ] + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + } + } +} +``` + +
+

+ +### Example 3: _Private access_ + +This instance deploys the module with private access only. + + +

+ +via Bicep module + +```bicep +module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:' = { + name: '${uniqueString(deployment().name, location)}-test-dfpsfspvt' + params: { + // Required parameters + name: 'dfpsfspvt001' + skuName: 'Standard_D2s_v3' + tier: 'GeneralPurpose' + // Non-required parameters + administratorLogin: 'adminUserName' + administratorLoginPassword: '' + configurations: [ + { + name: 'log_min_messages' + source: 'user-override' + value: 'INFO' + } + { + name: 'autovacuum_naptime' + source: 'user-override' + value: '80' + } + ] + databases: [ + { + charset: 'UTF8' + collation: 'en_US.utf8' + name: 'testdb1' + } + { + name: 'testdb2' + } + ] + delegatedSubnetResourceId: '' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + geoRedundantBackup: 'Enabled' + location: '' + privateDnsZoneArmResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +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": "dfpsfspvt001" + }, + "skuName": { + "value": "Standard_D2s_v3" + }, + "tier": { + "value": "GeneralPurpose" + }, + // Non-required parameters + "administratorLogin": { + "value": "adminUserName" + }, + "administratorLoginPassword": { + "value": "" + }, + "configurations": { + "value": [ + { + "name": "log_min_messages", + "source": "user-override", + "value": "INFO" + }, + { + "name": "autovacuum_naptime", + "source": "user-override", + "value": "80" + } + ] + }, + "databases": { + "value": [ + { + "charset": "UTF8", + "collation": "en_US.utf8", + "name": "testdb1" + }, + { + "name": "testdb2" + } + ] + }, + "delegatedSubnetResourceId": { + "value": "" + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "geoRedundantBackup": { + "value": "Enabled" + }, + "location": { + "value": "" + }, + "privateDnsZoneArmResourceId": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +### Example 4: _Public access_ + +This instance deploys the module with public access. + + +

+ +via Bicep module + +```bicep +module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:' = { + name: '${uniqueString(deployment().name, location)}-test-dfpsfsp' + params: { + // Required parameters + name: 'dfpsfsp001' + skuName: 'Standard_D2s_v3' + tier: 'GeneralPurpose' + // Non-required parameters + administrators: [ + { + objectId: '' + principalName: '' + principalType: 'ServicePrincipal' + } + ] + availabilityZone: '1' + backupRetentionDays: 20 + configurations: [ + { + name: 'log_min_messages' + source: 'user-override' + value: 'INFO' + } + ] + databases: [ + { + charset: 'UTF8' + collation: 'en_US.utf8' + name: 'testdb1' + } + { + name: 'testdb2' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + firewallRules: [ + { + endIpAddress: '0.0.0.0' + name: 'AllowAllWindowsAzureIps' + startIpAddress: '0.0.0.0' + } + { + endIpAddress: '10.10.10.10' + name: 'test-rule1' + startIpAddress: '10.10.10.1' + } + { + endIpAddress: '100.100.100.10' + name: 'test-rule2' + startIpAddress: '100.100.100.1' + } + ] + geoRedundantBackup: 'Disabled' + highAvailability: 'SameZone' + location: '' + storageSizeGB: 1024 + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + version: '14' + } +} +``` + +
+

+ +

+ +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": "dfpsfsp001" + }, + "skuName": { + "value": "Standard_D2s_v3" + }, + "tier": { + "value": "GeneralPurpose" + }, + // Non-required parameters + "administrators": { + "value": [ + { + "objectId": "", + "principalName": "", + "principalType": "ServicePrincipal" + } + ] + }, + "availabilityZone": { + "value": "1" + }, + "backupRetentionDays": { + "value": 20 + }, + "configurations": { + "value": [ + { + "name": "log_min_messages", + "source": "user-override", + "value": "INFO" + } + ] + }, + "databases": { + "value": [ + { + "charset": "UTF8", + "collation": "en_US.utf8", + "name": "testdb1" + }, + { + "name": "testdb2" + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "firewallRules": { + "value": [ + { + "endIpAddress": "0.0.0.0", + "name": "AllowAllWindowsAzureIps", + "startIpAddress": "0.0.0.0" + }, + { + "endIpAddress": "10.10.10.10", + "name": "test-rule1", + "startIpAddress": "10.10.10.1" + }, + { + "endIpAddress": "100.100.100.10", + "name": "test-rule2", + "startIpAddress": "100.100.100.1" + } + ] + }, + "geoRedundantBackup": { + "value": "Disabled" + }, + "highAvailability": { + "value": "SameZone" + }, + "location": { + "value": "" + }, + "storageSizeGB": { + "value": 1024 + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "version": { + "value": "14" + } + } +} +``` + +
+

+ +### Example 5: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:' = { + name: '${uniqueString(deployment().name, location)}-test-dfpsfswaf' + params: { + // Required parameters + name: 'dfpsfswaf001' + skuName: 'Standard_D2s_v3' + tier: 'GeneralPurpose' + // Non-required parameters + administrators: [ + { + objectId: '' + principalName: '' + principalType: 'ServicePrincipal' + } + ] + configurations: [ + { + name: 'log_min_messages' + source: 'user-override' + value: 'INFO' + } + { + name: 'autovacuum_naptime' + source: 'user-override' + value: '80' + } + ] + databases: [ + { + charset: 'UTF8' + collation: 'en_US.utf8' + name: 'testdb1' + } + { + name: 'testdb2' + } + ] + delegatedSubnetResourceId: '' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + geoRedundantBackup: 'Enabled' + location: '' + privateDnsZoneArmResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +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": "dfpsfswaf001" + }, + "skuName": { + "value": "Standard_D2s_v3" + }, + "tier": { + "value": "GeneralPurpose" + }, + // Non-required parameters + "administrators": { + "value": [ + { + "objectId": "", + "principalName": "", + "principalType": "ServicePrincipal" + } + ] + }, + "configurations": { + "value": [ + { + "name": "log_min_messages", + "source": "user-override", + "value": "INFO" + }, + { + "name": "autovacuum_naptime", + "source": "user-override", + "value": "80" + } + ] + }, + "databases": { + "value": [ + { + "charset": "UTF8", + "collation": "en_US.utf8", + "name": "testdb1" + }, + { + "name": "testdb2" + } + ] + }, + "delegatedSubnetResourceId": { + "value": "" + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "geoRedundantBackup": { + "value": "Enabled" + }, + "location": { + "value": "" + }, + "privateDnsZoneArmResourceId": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the PostgreSQL flexible server. | +| [`skuName`](#parameter-skuname) | string | The name of the sku, typically, tier + family + cores, e.g. Standard_D4s_v3. | +| [`tier`](#parameter-tier) | string | The tier of the particular SKU. Tier must align with the "skuName" property. Example, tier cannot be "Burstable" if skuName is "Standard_D4s_v3". | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. Required if 'cMKKeyName' is not empty. | +| [`pointInTimeUTC`](#parameter-pointintimeutc) | string | Required if "createMode" is set to "PointInTimeRestore". | +| [`sourceServerResourceId`](#parameter-sourceserverresourceid) | string | Required if "createMode" is set to "PointInTimeRestore". | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`activeDirectoryAuth`](#parameter-activedirectoryauth) | string | If Enabled, Azure Active Directory authentication is enabled. | +| [`administratorLogin`](#parameter-administratorlogin) | string | The administrator login name of a server. Can only be specified when the PostgreSQL server is being created. | +| [`administratorLoginPassword`](#parameter-administratorloginpassword) | securestring | The administrator login password. | +| [`administrators`](#parameter-administrators) | array | The Azure AD administrators when AAD authentication enabled. | +| [`availabilityZone`](#parameter-availabilityzone) | string | Availability zone information of the server. Default will have no preference set. | +| [`backupRetentionDays`](#parameter-backupretentiondays) | int | Backup retention days for the server. | +| [`configurations`](#parameter-configurations) | array | The configurations to create in the server. | +| [`createMode`](#parameter-createmode) | string | The mode to create a new PostgreSQL server. | +| [`customerManagedKey`](#parameter-customermanagedkey) | object | The customer managed key definition. | +| [`databases`](#parameter-databases) | array | The databases to create in the server. | +| [`delegatedSubnetResourceId`](#parameter-delegatedsubnetresourceid) | string | Delegated subnet arm resource ID. Used when the desired connectivity mode is "Private Access" - virtual network integration. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`firewallRules`](#parameter-firewallrules) | array | The firewall rules to create in the PostgreSQL flexible server. | +| [`geoRedundantBackup`](#parameter-georedundantbackup) | string | A value indicating whether Geo-Redundant backup is enabled on the server. Should be left disabled if 'cMKKeyName' is not empty. | +| [`highAvailability`](#parameter-highavailability) | string | The mode for high availability. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`maintenanceWindow`](#parameter-maintenancewindow) | object | Properties for the maintenence window. If provided, "customWindow" property must exist and set to "Enabled". | +| [`passwordAuth`](#parameter-passwordauth) | string | If Enabled, password authentication is enabled. | +| [`privateDnsZoneArmResourceId`](#parameter-privatednszonearmresourceid) | string | Private dns zone arm resource ID. Used when the desired connectivity mode is "Private Access" and required when "delegatedSubnetResourceId" is used. The Private DNS Zone must be lined to the Virtual Network referenced in "delegatedSubnetResourceId". | +| [`roleAssignments`](#parameter-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'. | +| [`storageSizeGB`](#parameter-storagesizegb) | int | Max storage allowed for a server. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`tenantId`](#parameter-tenantid) | string | Tenant id of the server. | +| [`version`](#parameter-version) | string | PostgreSQL Server version. | + +### Parameter: `activeDirectoryAuth` + +If Enabled, Azure Active Directory authentication is enabled. +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `administratorLogin` + +The administrator login name of a server. Can only be specified when the PostgreSQL server is being created. +- Required: No +- Type: string +- Default: `''` + +### Parameter: `administratorLoginPassword` + +The administrator login password. +- Required: No +- Type: securestring +- Default: `''` + +### Parameter: `administrators` + +The Azure AD administrators when AAD authentication enabled. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `availabilityZone` + +Availability zone information of the server. Default will have no preference set. +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + '1' + '2' + '3' + ] + ``` + +### Parameter: `backupRetentionDays` + +Backup retention days for the server. +- Required: No +- Type: int +- Default: `7` + +### Parameter: `configurations` + +The configurations to create in the server. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `createMode` + +The mode to create a new PostgreSQL server. +- Required: No +- Type: string +- Default: `'Default'` +- Allowed: + ```Bicep + [ + 'Create' + 'Default' + 'PointInTimeRestore' + 'Update' + ] + ``` + +### Parameter: `customerManagedKey` + +The customer managed key definition. +- Required: No +- Type: object + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`keyName`](#parameter-customermanagedkeykeyname) | Yes | string | Required. The name of the customer managed key to use for encryption. | +| [`keyVaultResourceId`](#parameter-customermanagedkeykeyvaultresourceid) | Yes | string | Required. The resource ID of a key vault to reference a customer managed key for encryption from. | +| [`keyVersion`](#parameter-customermanagedkeykeyversion) | No | string | Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'. | +| [`userAssignedIdentityResourceId`](#parameter-customermanagedkeyuserassignedidentityresourceid) | Yes | string | Required. User assigned identity to use when fetching the customer managed key. | + +### Parameter: `customerManagedKey.keyName` + +Required. The name of the customer managed key to use for encryption. + +- Required: Yes +- Type: string + +### Parameter: `customerManagedKey.keyVaultResourceId` + +Required. The resource ID of a key vault to reference a customer managed key for encryption from. + +- Required: Yes +- Type: string + +### Parameter: `customerManagedKey.keyVersion` + +Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'. + +- Required: No +- Type: string + +### Parameter: `customerManagedKey.userAssignedIdentityResourceId` + +Required. User assigned identity to use when fetching the customer managed key. + +- Required: Yes +- Type: string + +### Parameter: `databases` + +The databases to create in the server. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `delegatedSubnetResourceId` + +Delegated subnet arm resource ID. Used when the desired connectivity mode is "Private Access" - virtual network integration. +- Required: No +- Type: string +- Default: `''` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. +- Required: No +- Type: array + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | No | string | 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. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | No | string | 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. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | No | string | Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | No | array | Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | No | string | Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | No | array | Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. | +| [`name`](#parameter-diagnosticsettingsname) | No | string | Optional. The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | No | string | 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. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | No | string | 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. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +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. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +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. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: `[AzureDiagnostics, Dedicated]` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. + +- Required: No +- Type: array + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | No | string | Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | No | string | Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to 'AllLogs' to collect all logs. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to 'AllLogs' to collect all logs. + +- Required: No +- Type: string + + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. + +- Required: No +- Type: array + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | Yes | string | Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to 'AllMetrics' to collect all metrics. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to 'AllMetrics' to collect all metrics. + +- Required: Yes +- Type: string + + +### Parameter: `diagnosticSettings.name` + +Optional. The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +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. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +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. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `firewallRules` + +The firewall rules to create in the PostgreSQL flexible server. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `geoRedundantBackup` + +A value indicating whether Geo-Redundant backup is enabled on the server. Should be left disabled if 'cMKKeyName' is not empty. +- Required: No +- Type: string +- Default: `'Disabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `highAvailability` + +The mode for high availability. +- Required: No +- Type: string +- Default: `'Disabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'SameZone' + 'ZoneRedundant' + ] + ``` + +### Parameter: `location` + +Location for all resources. +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. +- Required: No +- Type: object + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`kind`](#parameter-lockkind) | No | string | Optional. Specify the type of lock. | +| [`name`](#parameter-lockname) | No | string | Optional. Specify the name of lock. | + +### Parameter: `lock.kind` + +Optional. Specify the type of lock. + +- Required: No +- Type: string +- Allowed: `[CanNotDelete, None, ReadOnly]` + +### Parameter: `lock.name` + +Optional. Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `maintenanceWindow` + +Properties for the maintenence window. If provided, "customWindow" property must exist and set to "Enabled". +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. Required if 'cMKKeyName' is not empty. +- Required: No +- Type: object + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | Yes | array | Optional. The resource ID(s) to assign to the resource. | + +### Parameter: `managedIdentities.userAssignedResourceIds` + +Optional. The resource ID(s) to assign to the resource. + +- Required: Yes +- Type: array + +### Parameter: `name` + +The name of the PostgreSQL flexible server. +- Required: Yes +- Type: string + +### Parameter: `passwordAuth` + +If Enabled, password authentication is enabled. +- Required: No +- Type: string +- Default: `'Disabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `pointInTimeUTC` + +Required if "createMode" is set to "PointInTimeRestore". +- Required: No +- Type: string +- Default: `''` + +### Parameter: `privateDnsZoneArmResourceId` + +Private dns zone arm resource ID. Used when the desired connectivity mode is "Private Access" and required when "delegatedSubnetResourceId" is used. The Private DNS Zone must be lined to the Virtual Network referenced in "delegatedSubnetResourceId". +- Required: No +- Type: string +- Default: `''` + +### Parameter: `roleAssignments` + +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'. +- Required: No +- Type: array + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`condition`](#parameter-roleassignmentscondition) | No | string | 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" | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | No | string | Optional. Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | No | string | Optional. The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | +| [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | + +### Parameter: `roleAssignments.condition` + +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" + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Optional. Version of the condition. + +- Required: No +- Type: string +- Allowed: `[2.0]` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +Optional. The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +Optional. The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalId` + +Required. The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.principalType` + +Optional. The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: `[Device, ForeignGroup, Group, ServicePrincipal, User]` + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. + +- Required: Yes +- Type: string + +### Parameter: `skuName` + +The name of the sku, typically, tier + family + cores, e.g. Standard_D4s_v3. +- Required: Yes +- Type: string + +### Parameter: `sourceServerResourceId` + +Required if "createMode" is set to "PointInTimeRestore". +- Required: No +- Type: string +- Default: `''` + +### Parameter: `storageSizeGB` + +Max storage allowed for a server. +- Required: No +- Type: int +- Default: `32` +- Allowed: + ```Bicep + [ + 32 + 64 + 128 + 256 + 512 + 1024 + 2048 + 4096 + 8192 + 16384 + ] + ``` + +### Parameter: `tags` + +Tags of the resource. +- Required: No +- Type: object + +### Parameter: `tenantId` + +Tenant id of the server. +- Required: No +- Type: string +- Default: `''` + +### Parameter: `tier` + +The tier of the particular SKU. Tier must align with the "skuName" property. Example, tier cannot be "Burstable" if skuName is "Standard_D4s_v3". +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Burstable' + 'GeneralPurpose' + 'MemoryOptimized' + ] + ``` + +### Parameter: `version` + +PostgreSQL Server version. +- Required: No +- Type: string +- Default: `'15'` +- Allowed: + ```Bicep + [ + '11' + '12' + '13' + '14' + '15' + ] + ``` + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployed PostgreSQL Flexible server. | +| `resourceGroupName` | string | The resource group of the deployed PostgreSQL Flexible server. | +| `resourceId` | string | The resource ID of the deployed PostgreSQL Flexible server. | + +## Cross-referenced modules + +_None_ diff --git a/avm/res/db-for-postgre-sql/flexible-server/administrator/README.md b/avm/res/db-for-postgre-sql/flexible-server/administrator/README.md new file mode 100644 index 0000000000..c3c8ac46d0 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/administrator/README.md @@ -0,0 +1,91 @@ +# DBforPostgreSQL Flexible Server Administrators `[Microsoft.DBforPostgreSQL/flexibleServers/administrators]` + +This module deploys a DBforPostgreSQL Flexible Server Administrator. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.DBforPostgreSQL/flexibleServers/administrators` | [2022-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforPostgreSQL/2022-12-01/flexibleServers/administrators) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`objectId`](#parameter-objectid) | string | The objectId of the Active Directory administrator. | +| [`principalName`](#parameter-principalname) | string | Active Directory administrator principal name. | +| [`principalType`](#parameter-principaltype) | string | The principal type used to represent the type of Active Directory Administrator. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`flexibleServerName`](#parameter-flexibleservername) | string | The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`tenantId`](#parameter-tenantid) | string | The tenantId of the Active Directory administrator. | + +### Parameter: `flexibleServerName` + +The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment. +- Required: Yes +- Type: string + +### Parameter: `objectId` + +The objectId of the Active Directory administrator. +- Required: Yes +- Type: string + +### Parameter: `principalName` + +Active Directory administrator principal name. +- Required: Yes +- Type: string + +### Parameter: `principalType` + +The principal type used to represent the type of Active Directory Administrator. +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Group' + 'ServicePrincipal' + 'Unknown' + 'User' + ] + ``` + +### Parameter: `tenantId` + +The tenantId of the Active Directory administrator. +- Required: No +- Type: string +- Default: `[tenant().tenantId]` + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed administrator. | +| `resourceGroupName` | string | The resource group of the deployed administrator. | +| `resourceId` | string | The resource ID of the deployed administrator. | + +## Cross-referenced modules + +_None_ diff --git a/avm/res/db-for-postgre-sql/flexible-server/administrator/main.bicep b/avm/res/db-for-postgre-sql/flexible-server/administrator/main.bicep new file mode 100644 index 0000000000..cfbf7f0880 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/administrator/main.bicep @@ -0,0 +1,47 @@ +metadata name = 'DBforPostgreSQL Flexible Server Administrators' +metadata description = 'This module deploys a DBforPostgreSQL Flexible Server Administrator.' +metadata owner = 'Azure/module-maintainers' + +@description('Conditional. The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment.') +param flexibleServerName string + +@description('Required. The objectId of the Active Directory administrator.') +param objectId string + +@description('Required. Active Directory administrator principal name.') +param principalName string + +@allowed([ + 'Group' + 'ServicePrincipal' + 'Unknown' + 'User' +]) +@description('Required. The principal type used to represent the type of Active Directory Administrator.') +param principalType string + +@description('Optional. The tenantId of the Active Directory administrator.') +param tenantId string = tenant().tenantId + +resource flexibleServer 'Microsoft.DBforPostgreSQL/flexibleServers@2022-12-01' existing = { + name: flexibleServerName +} + +resource administrator 'Microsoft.DBforPostgreSQL/flexibleServers/administrators@2022-12-01' = { + name: objectId + parent: flexibleServer + properties: { + principalName: principalName + principalType: principalType + tenantId: tenantId + } +} + +@description('The name of the deployed administrator.') +output name string = administrator.name + +@description('The resource ID of the deployed administrator.') +output resourceId string = administrator.id + +@description('The resource group of the deployed administrator.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/res/db-for-postgre-sql/flexible-server/administrator/main.json b/avm/res/db-for-postgre-sql/flexible-server/administrator/main.json new file mode 100644 index 0000000000..e375d86247 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/administrator/main.json @@ -0,0 +1,88 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "14731498034273397058" + }, + "name": "DBforPostgreSQL Flexible Server Administrators", + "description": "This module deploys a DBforPostgreSQL Flexible Server Administrator.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "flexibleServerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The objectId of the Active Directory administrator." + } + }, + "principalName": { + "type": "string", + "metadata": { + "description": "Required. Active Directory administrator principal name." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Group", + "ServicePrincipal", + "Unknown", + "User" + ], + "metadata": { + "description": "Required. The principal type used to represent the type of Active Directory Administrator." + } + }, + "tenantId": { + "type": "string", + "defaultValue": "[tenant().tenantId]", + "metadata": { + "description": "Optional. The tenantId of the Active Directory administrator." + } + } + }, + "resources": [ + { + "type": "Microsoft.DBforPostgreSQL/flexibleServers/administrators", + "apiVersion": "2022-12-01", + "name": "[format('{0}/{1}', parameters('flexibleServerName'), parameters('objectId'))]", + "properties": { + "principalName": "[parameters('principalName')]", + "principalType": "[parameters('principalType')]", + "tenantId": "[parameters('tenantId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed administrator." + }, + "value": "[parameters('objectId')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed administrator." + }, + "value": "[resourceId('Microsoft.DBforPostgreSQL/flexibleServers/administrators', parameters('flexibleServerName'), parameters('objectId'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed administrator." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/res/db-for-postgre-sql/flexible-server/configuration/README.md b/avm/res/db-for-postgre-sql/flexible-server/configuration/README.md new file mode 100644 index 0000000000..ed88305ee0 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/configuration/README.md @@ -0,0 +1,76 @@ +# DBforPostgreSQL Flexible Server Configurations `[Microsoft.DBforPostgreSQL/flexibleServers/configurations]` + +This module deploys a DBforPostgreSQL Flexible Server Configuration. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.DBforPostgreSQL/flexibleServers/configurations` | [2022-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforPostgreSQL/2022-12-01/flexibleServers/configurations) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the configuration. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`flexibleServerName`](#parameter-flexibleservername) | string | The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`source`](#parameter-source) | string | Source of the configuration. | +| [`value`](#parameter-value) | string | Value of the configuration. | + +### Parameter: `flexibleServerName` + +The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment. +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the configuration. +- Required: Yes +- Type: string + +### Parameter: `source` + +Source of the configuration. +- Required: No +- Type: string +- Default: `''` + +### Parameter: `value` + +Value of the configuration. +- Required: No +- Type: string +- Default: `''` + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed configuration. | +| `resourceGroupName` | string | The resource group of the deployed configuration. | +| `resourceId` | string | The resource ID of the deployed configuration. | + +## Cross-referenced modules + +_None_ diff --git a/avm/res/db-for-postgre-sql/flexible-server/configuration/main.bicep b/avm/res/db-for-postgre-sql/flexible-server/configuration/main.bicep new file mode 100644 index 0000000000..1a883000e9 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/configuration/main.bicep @@ -0,0 +1,37 @@ +metadata name = 'DBforPostgreSQL Flexible Server Configurations' +metadata description = 'This module deploys a DBforPostgreSQL Flexible Server Configuration.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the configuration.') +param name string + +@description('Conditional. The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment.') +param flexibleServerName string + +@description('Optional. Source of the configuration.') +param source string = '' + +@description('Optional. Value of the configuration.') +param value string = '' + +resource flexibleServer 'Microsoft.DBforPostgreSQL/flexibleServers@2022-12-01' existing = { + name: flexibleServerName +} + +resource configuration 'Microsoft.DBforPostgreSQL/flexibleServers/configurations@2022-12-01' = { + name: name + parent: flexibleServer + properties: { + source: !empty(source) ? source : null + value: !empty(value) ? value : null + } +} + +@description('The name of the deployed configuration.') +output name string = configuration.name + +@description('The resource ID of the deployed configuration.') +output resourceId string = configuration.id + +@description('The resource group of the deployed configuration.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/res/db-for-postgre-sql/flexible-server/configuration/main.json b/avm/res/db-for-postgre-sql/flexible-server/configuration/main.json new file mode 100644 index 0000000000..6a5818cac5 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/configuration/main.json @@ -0,0 +1,76 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "12646520601030472128" + }, + "name": "DBforPostgreSQL Flexible Server Configurations", + "description": "This module deploys a DBforPostgreSQL Flexible Server Configuration.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the configuration." + } + }, + "flexibleServerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment." + } + }, + "source": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Source of the configuration." + } + }, + "value": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Value of the configuration." + } + } + }, + "resources": [ + { + "type": "Microsoft.DBforPostgreSQL/flexibleServers/configurations", + "apiVersion": "2022-12-01", + "name": "[format('{0}/{1}', parameters('flexibleServerName'), parameters('name'))]", + "properties": { + "source": "[if(not(empty(parameters('source'))), parameters('source'), null())]", + "value": "[if(not(empty(parameters('value'))), parameters('value'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed configuration." + }, + "value": "[resourceId('Microsoft.DBforPostgreSQL/flexibleServers/configurations', parameters('flexibleServerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed configuration." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/res/db-for-postgre-sql/flexible-server/database/README.md b/avm/res/db-for-postgre-sql/flexible-server/database/README.md new file mode 100644 index 0000000000..8852b5c565 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/database/README.md @@ -0,0 +1,76 @@ +# DBforPostgreSQL Flexible Server Databases `[Microsoft.DBforPostgreSQL/flexibleServers/databases]` + +This module deploys a DBforPostgreSQL Flexible Server Database. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.DBforPostgreSQL/flexibleServers/databases` | [2022-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforPostgreSQL/2022-12-01/flexibleServers/databases) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the database. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`flexibleServerName`](#parameter-flexibleservername) | string | The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`charset`](#parameter-charset) | string | The charset of the database. | +| [`collation`](#parameter-collation) | string | The collation of the database. | + +### Parameter: `charset` + +The charset of the database. +- Required: No +- Type: string +- Default: `''` + +### Parameter: `collation` + +The collation of the database. +- Required: No +- Type: string +- Default: `''` + +### Parameter: `flexibleServerName` + +The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment. +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the database. +- Required: Yes +- Type: string + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed database. | +| `resourceGroupName` | string | The resource group of the deployed database. | +| `resourceId` | string | The resource ID of the deployed database. | + +## Cross-referenced modules + +_None_ diff --git a/avm/res/db-for-postgre-sql/flexible-server/database/main.bicep b/avm/res/db-for-postgre-sql/flexible-server/database/main.bicep new file mode 100644 index 0000000000..3e5cbdf09b --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/database/main.bicep @@ -0,0 +1,37 @@ +metadata name = 'DBforPostgreSQL Flexible Server Databases' +metadata description = 'This module deploys a DBforPostgreSQL Flexible Server Database.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the database.') +param name string + +@description('Conditional. The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment.') +param flexibleServerName string + +@description('Optional. The collation of the database.') +param collation string = '' + +@description('Optional. The charset of the database.') +param charset string = '' + +resource flexibleServer 'Microsoft.DBforPostgreSQL/flexibleServers@2022-12-01' existing = { + name: flexibleServerName +} + +resource database 'Microsoft.DBforPostgreSQL/flexibleServers/databases@2022-12-01' = { + name: name + parent: flexibleServer + properties: { + collation: !empty(collation) ? collation : null + charset: !empty(charset) ? charset : null + } +} + +@description('The name of the deployed database.') +output name string = database.name + +@description('The resource ID of the deployed database.') +output resourceId string = database.id + +@description('The resource group of the deployed database.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/res/db-for-postgre-sql/flexible-server/database/main.json b/avm/res/db-for-postgre-sql/flexible-server/database/main.json new file mode 100644 index 0000000000..f251211f47 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/database/main.json @@ -0,0 +1,76 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "2692846763140379246" + }, + "name": "DBforPostgreSQL Flexible Server Databases", + "description": "This module deploys a DBforPostgreSQL Flexible Server Database.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the database." + } + }, + "flexibleServerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment." + } + }, + "collation": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The collation of the database." + } + }, + "charset": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The charset of the database." + } + } + }, + "resources": [ + { + "type": "Microsoft.DBforPostgreSQL/flexibleServers/databases", + "apiVersion": "2022-12-01", + "name": "[format('{0}/{1}', parameters('flexibleServerName'), parameters('name'))]", + "properties": { + "collation": "[if(not(empty(parameters('collation'))), parameters('collation'), null())]", + "charset": "[if(not(empty(parameters('charset'))), parameters('charset'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed database." + }, + "value": "[resourceId('Microsoft.DBforPostgreSQL/flexibleServers/databases', parameters('flexibleServerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed database." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/res/db-for-postgre-sql/flexible-server/firewall-rule/README.md b/avm/res/db-for-postgre-sql/flexible-server/firewall-rule/README.md new file mode 100644 index 0000000000..3f84301fde --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/firewall-rule/README.md @@ -0,0 +1,69 @@ +# DBforPostgreSQL Flexible Server Firewall Rules `[Microsoft.DBforPostgreSQL/flexibleServers/firewallRules]` + +This module deploys a DBforPostgreSQL Flexible Server Firewall Rule. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.DBforPostgreSQL/flexibleServers/firewallRules` | [2022-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforPostgreSQL/2022-12-01/flexibleServers/firewallRules) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`endIpAddress`](#parameter-endipaddress) | string | The end IP address of the firewall rule. Must be IPv4 format. Must be greater than or equal to startIpAddress. Use value '0.0.0.0' for all Azure-internal IP addresses. | +| [`name`](#parameter-name) | string | The name of the PostgreSQL flexible server Firewall Rule. | +| [`startIpAddress`](#parameter-startipaddress) | string | The start IP address of the firewall rule. Must be IPv4 format. Use value '0.0.0.0' for all Azure-internal IP addresses. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`flexibleServerName`](#parameter-flexibleservername) | string | The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment. | + +### Parameter: `endIpAddress` + +The end IP address of the firewall rule. Must be IPv4 format. Must be greater than or equal to startIpAddress. Use value '0.0.0.0' for all Azure-internal IP addresses. +- Required: Yes +- Type: string + +### Parameter: `flexibleServerName` + +The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment. +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the PostgreSQL flexible server Firewall Rule. +- Required: Yes +- Type: string + +### Parameter: `startIpAddress` + +The start IP address of the firewall rule. Must be IPv4 format. Use value '0.0.0.0' for all Azure-internal IP addresses. +- Required: Yes +- Type: string + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed firewall rule. | +| `resourceGroupName` | string | The resource group of the deployed firewall rule. | +| `resourceId` | string | The resource ID of the deployed firewall rule. | + +## Cross-referenced modules + +_None_ diff --git a/avm/res/db-for-postgre-sql/flexible-server/firewall-rule/main.bicep b/avm/res/db-for-postgre-sql/flexible-server/firewall-rule/main.bicep new file mode 100644 index 0000000000..862bb93ecc --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/firewall-rule/main.bicep @@ -0,0 +1,37 @@ +metadata name = 'DBforPostgreSQL Flexible Server Firewall Rules' +metadata description = 'This module deploys a DBforPostgreSQL Flexible Server Firewall Rule.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the PostgreSQL flexible server Firewall Rule.') +param name string + +@description('Required. The start IP address of the firewall rule. Must be IPv4 format. Use value \'0.0.0.0\' for all Azure-internal IP addresses.') +param startIpAddress string + +@description('Required. The end IP address of the firewall rule. Must be IPv4 format. Must be greater than or equal to startIpAddress. Use value \'0.0.0.0\' for all Azure-internal IP addresses.') +param endIpAddress string + +@description('Conditional. The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment.') +param flexibleServerName string + +resource flexibleServer 'Microsoft.DBforPostgreSQL/flexibleServers@2022-12-01' existing = { + name: flexibleServerName +} + +resource firewallRule 'Microsoft.DBforPostgreSQL/flexibleServers/firewallRules@2022-12-01' = { + name: name + parent: flexibleServer + properties: { + endIpAddress: endIpAddress + startIpAddress: startIpAddress + } +} + +@description('The name of the deployed firewall rule.') +output name string = firewallRule.name + +@description('The resource ID of the deployed firewall rule.') +output resourceId string = firewallRule.id + +@description('The resource group of the deployed firewall rule.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/res/db-for-postgre-sql/flexible-server/firewall-rule/main.json b/avm/res/db-for-postgre-sql/flexible-server/firewall-rule/main.json new file mode 100644 index 0000000000..e352e185c3 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/firewall-rule/main.json @@ -0,0 +1,74 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "6933053371627105806" + }, + "name": "DBforPostgreSQL Flexible Server Firewall Rules", + "description": "This module deploys a DBforPostgreSQL Flexible Server Firewall Rule.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the PostgreSQL flexible server Firewall Rule." + } + }, + "startIpAddress": { + "type": "string", + "metadata": { + "description": "Required. The start IP address of the firewall rule. Must be IPv4 format. Use value '0.0.0.0' for all Azure-internal IP addresses." + } + }, + "endIpAddress": { + "type": "string", + "metadata": { + "description": "Required. The end IP address of the firewall rule. Must be IPv4 format. Must be greater than or equal to startIpAddress. Use value '0.0.0.0' for all Azure-internal IP addresses." + } + }, + "flexibleServerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment." + } + } + }, + "resources": [ + { + "type": "Microsoft.DBforPostgreSQL/flexibleServers/firewallRules", + "apiVersion": "2022-12-01", + "name": "[format('{0}/{1}', parameters('flexibleServerName'), parameters('name'))]", + "properties": { + "endIpAddress": "[parameters('endIpAddress')]", + "startIpAddress": "[parameters('startIpAddress')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed firewall rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed firewall rule." + }, + "value": "[resourceId('Microsoft.DBforPostgreSQL/flexibleServers/firewallRules', parameters('flexibleServerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed firewall rule." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/res/db-for-postgre-sql/flexible-server/main.bicep b/avm/res/db-for-postgre-sql/flexible-server/main.bicep new file mode 100644 index 0000000000..55a397e9e9 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/main.bicep @@ -0,0 +1,455 @@ +metadata name = 'DBforPostgreSQL Flexible Servers' +metadata description = 'This module deploys a DBforPostgreSQL Flexible Server.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the PostgreSQL flexible server.') +param name string + +@description('Optional. The administrator login name of a server. Can only be specified when the PostgreSQL server is being created.') +param administratorLogin string = '' + +@description('Optional. The administrator login password.') +@secure() +param administratorLoginPassword string = '' + +@allowed([ + 'Disabled' + 'Enabled' +]) +@description('Optional. If Enabled, Azure Active Directory authentication is enabled.') +param activeDirectoryAuth string = 'Enabled' + +@allowed([ + 'Disabled' + 'Enabled' +]) +@description('Optional. If Enabled, password authentication is enabled.') +#disable-next-line secure-secrets-in-params +param passwordAuth string = 'Disabled' + +@description('Optional. Tenant id of the server.') +param tenantId string = '' + +@description('Optional. The Azure AD administrators when AAD authentication enabled.') +param administrators array = [] + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Required. The name of the sku, typically, tier + family + cores, e.g. Standard_D4s_v3.') +param skuName string + +@allowed([ + 'GeneralPurpose' + 'Burstable' + 'MemoryOptimized' +]) +@description('Required. The tier of the particular SKU. Tier must align with the "skuName" property. Example, tier cannot be "Burstable" if skuName is "Standard_D4s_v3".') +param tier string + +@allowed([ + '' + '1' + '2' + '3' +]) +@description('Optional. Availability zone information of the server. Default will have no preference set.') +param availabilityZone string = '' + +@minValue(7) +@maxValue(35) +@description('Optional. Backup retention days for the server.') +param backupRetentionDays int = 7 + +@allowed([ + 'Disabled' + 'Enabled' +]) +@description('Optional. A value indicating whether Geo-Redundant backup is enabled on the server. Should be left disabled if \'cMKKeyName\' is not empty.') +param geoRedundantBackup string = 'Disabled' + +@allowed([ + 32 + 64 + 128 + 256 + 512 + 1024 + 2048 + 4096 + 8192 + 16384 +]) +@description('Optional. Max storage allowed for a server.') +param storageSizeGB int = 32 + +@allowed([ + '11' + '12' + '13' + '14' + '15' +]) +@description('Optional. PostgreSQL Server version.') +param version string = '15' + +@allowed([ + 'Disabled' + 'SameZone' + 'ZoneRedundant' +]) +@description('Optional. The mode for high availability.') +param highAvailability string = 'Disabled' + +@allowed([ + 'Create' + 'Default' + 'PointInTimeRestore' + 'Update' +]) +@description('Optional. The mode to create a new PostgreSQL server.') +param createMode string = 'Default' + +@description('Conditional. The managed identity definition for this resource. Required if \'cMKKeyName\' is not empty.') +param managedIdentities managedIdentitiesType + +@description('Optional. The customer managed key definition.') +param customerManagedKey customerManagedKeyType + +@description('Optional. Properties for the maintenence window. If provided, "customWindow" property must exist and set to "Enabled".') +param maintenanceWindow object = {} + +@description('Conditional. Required if "createMode" is set to "PointInTimeRestore".') +param pointInTimeUTC string = '' + +@description('Conditional. Required if "createMode" is set to "PointInTimeRestore".') +param sourceServerResourceId string = '' + +@description('Optional. Delegated subnet arm resource ID. Used when the desired connectivity mode is "Private Access" - virtual network integration.') +param delegatedSubnetResourceId string = '' + +@description('Optional. Private dns zone arm resource ID. Used when the desired connectivity mode is "Private Access" and required when "delegatedSubnetResourceId" is used. The Private DNS Zone must be lined to the Virtual Network referenced in "delegatedSubnetResourceId".') +param privateDnsZoneArmResourceId string = '' + +@description('Optional. The firewall rules to create in the PostgreSQL flexible server.') +param firewallRules array = [] + +@description('Optional. The databases to create in the server.') +param databases array = [] + +@description('Optional. The configurations to create in the server.') +param configurations array = [] + +@description('Optional. The lock settings of the service.') +param lock lockType + +@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 roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +var formattedUserAssignedIdentities = reduce(map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), {}, (cur, next) => union(cur, next)) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) ? { + type: !empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null +} : null + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + '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 avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: '46d3xbcp.res.dbforpostgresql-flexibleserver.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource cMKKeyVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId)) { + name: last(split((customerManagedKey.?keyVaultResourceId ?? 'dummyVault'), '/')) + scope: resourceGroup(split((customerManagedKey.?keyVaultResourceId ?? '//'), '/')[2], split((customerManagedKey.?keyVaultResourceId ?? '////'), '/')[4]) + + resource cMKKey 'keys@2023-07-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId) && !empty(customerManagedKey.?keyName)) { + name: customerManagedKey.?keyName ?? 'dummyKey' + } +} + +resource cMKUserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = if (!empty(customerManagedKey.?userAssignedIdentityResourceId)) { + name: last(split(customerManagedKey.?userAssignedIdentityResourceId ?? 'dummyMsi', '/')) + scope: resourceGroup(split((customerManagedKey.?userAssignedIdentityResourceId ?? '//'), '/')[2], split((customerManagedKey.?userAssignedIdentityResourceId ?? '////'), '/')[4]) +} + +resource flexibleServer 'Microsoft.DBforPostgreSQL/flexibleServers@2022-12-01' = { + name: name + location: location + tags: tags + sku: { + name: skuName + tier: tier + } + identity: identity + properties: { + administratorLogin: !empty(administratorLogin) ? administratorLogin : null + administratorLoginPassword: !empty(administratorLoginPassword) ? administratorLoginPassword : null + authConfig: { + activeDirectoryAuth: activeDirectoryAuth + passwordAuth: passwordAuth + tenantId: !empty(tenantId) ? tenantId : null + } + availabilityZone: availabilityZone + backup: { + backupRetentionDays: backupRetentionDays + geoRedundantBackup: geoRedundantBackup + } + createMode: createMode + dataEncryption: !empty(customerManagedKey) ? { + primaryKeyURI: !empty(customerManagedKey.?keyVersion ?? '') ? '${cMKKeyVault::cMKKey.properties.keyUri}/${customerManagedKey!.keyVersion}' : cMKKeyVault::cMKKey.properties.keyUriWithVersion + primaryUserAssignedIdentityId: cMKUserAssignedIdentity.id + type: 'AzureKeyVault' + } : null + highAvailability: { + mode: highAvailability + standbyAvailabilityZone: highAvailability == 'SameZone' ? availabilityZone : null + } + maintenanceWindow: !empty(maintenanceWindow) ? { + customWindow: maintenanceWindow.customWindow + dayOfWeek: maintenanceWindow.customWindow == 'Enabled' ? maintenanceWindow.dayOfWeek : 0 + startHour: maintenanceWindow.customWindow == 'Enabled' ? maintenanceWindow.startHour : 0 + startMinute: maintenanceWindow.customWindow == 'Enabled' ? maintenanceWindow.startMinute : 0 + } : null + network: !empty(delegatedSubnetResourceId) && empty(firewallRules) ? { + delegatedSubnetResourceId: delegatedSubnetResourceId + privateDnsZoneArmResourceId: privateDnsZoneArmResourceId + } : null + pointInTimeUTC: createMode == 'PointInTimeRestore' ? pointInTimeUTC : null + sourceServerResourceId: createMode == 'PointInTimeRestore' ? sourceServerResourceId : null + storage: { + storageSizeGB: storageSizeGB + } + version: version + } +} + +resource flexibleServer_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' ? 'Cannot delete resource or child resources.' : 'Cannot delete or modify the resource or child resources.' + } + scope: flexibleServer +} + +resource flexibleServer_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { + name: guid(flexibleServer.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) + properties: { + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: flexibleServer +}] + +module flexibleServer_databases 'database/main.bicep' = [for (database, index) in databases: { + name: '${uniqueString(deployment().name, location)}-PostgreSQL-DB-${index}' + params: { + name: database.name + flexibleServerName: flexibleServer.name + collation: contains(database, 'collation') ? database.collation : '' + charset: contains(database, 'charset') ? database.charset : '' + } +}] + +module flexibleServer_firewallRules 'firewall-rule/main.bicep' = [for (firewallRule, index) in firewallRules: { + name: '${uniqueString(deployment().name, location)}-PostgreSQL-FirewallRules-${index}' + params: { + name: firewallRule.name + flexibleServerName: flexibleServer.name + startIpAddress: firewallRule.startIpAddress + endIpAddress: firewallRule.endIpAddress + } + dependsOn: [ + flexibleServer_databases + ] +}] + +@batchSize(1) +module flexibleServer_configurations 'configuration/main.bicep' = [for (configuration, index) in configurations: { + name: '${uniqueString(deployment().name, location)}-PostgreSQL-Configurations-${index}' + params: { + name: configuration.name + flexibleServerName: flexibleServer.name + source: contains(configuration, 'source') ? configuration.source : '' + value: contains(configuration, 'value') ? configuration.value : '' + } + dependsOn: [ + flexibleServer_firewallRules + ] +}] + +module flexibleServer_administrators 'administrator/main.bicep' = [for (administrator, index) in administrators: { + name: '${uniqueString(deployment().name, location)}-PostgreSQL-Administrators-${index}' + params: { + flexibleServerName: flexibleServer.name + objectId: administrator.objectId + principalName: administrator.principalName + principalType: administrator.principalType + tenantId: contains(administrator, 'tenantId') ? administrator.tenantId : tenant().tenantId + } +}] + +resource flexibleServer_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: diagnosticSetting.?metricCategories ?? [ + { + category: 'AllMetrics' + timeGrain: null + enabled: true + } + ] + logs: diagnosticSetting.?logCategoriesAndGroups ?? [ + { + categoryGroup: 'AllLogs' + enabled: true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: flexibleServer +}] + +@description('The name of the deployed PostgreSQL Flexible server.') +output name string = flexibleServer.name + +@description('The resource ID of the deployed PostgreSQL Flexible server.') +output resourceId string = flexibleServer.id + +@description('The resource group of the deployed PostgreSQL Flexible server.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = flexibleServer.location + +// =============== // +// Definitions // +// =============== // + +type managedIdentitiesType = { + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourceIds: string[] +}? + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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"') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to \'\' to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to \'AllLogs\' to collect all logs.') + categoryGroup: string? + }[]? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to \'\' to disable log collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to \'AllMetrics\' to collect all metrics.') + category: string + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @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.') + workspaceResourceId: string? + + @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.') + storageAccountResourceId: 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.') + eventHubAuthorizationRuleResourceId: 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.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? + +type customerManagedKeyType = { + @description('Required. The resource ID of a key vault to reference a customer managed key for encryption from.') + keyVaultResourceId: string + + @description('Required. The name of the customer managed key to use for encryption.') + keyName: string + + @description('Optional. The version of the customer managed key to reference for encryption. If not provided, using \'latest\'.') + keyVersion: string? + + @description('Required. User assigned identity to use when fetching the customer managed key.') + userAssignedIdentityResourceId: string +}? diff --git a/avm/res/db-for-postgre-sql/flexible-server/main.json b/avm/res/db-for-postgre-sql/flexible-server/main.json new file mode 100644 index 0000000000..67dd505ea2 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/main.json @@ -0,0 +1,1168 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "9838703870761845500" + }, + "name": "DBforPostgreSQL Flexible Servers", + "description": "This module deploys a DBforPostgreSQL Flexible Server.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to 'AllLogs' to collect all logs." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to '' to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to 'AllMetrics' to collect all metrics." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to '' to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "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." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "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." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "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." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "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." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "metadata": { + "description": "Required. User assigned identity to use when fetching the customer managed key." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the PostgreSQL flexible server." + } + }, + "administratorLogin": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The administrator login name of a server. Can only be specified when the PostgreSQL server is being created." + } + }, + "administratorLoginPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. The administrator login password." + } + }, + "activeDirectoryAuth": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. If Enabled, Azure Active Directory authentication is enabled." + } + }, + "passwordAuth": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. If Enabled, password authentication is enabled." + } + }, + "tenantId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Tenant id of the server." + } + }, + "administrators": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The Azure AD administrators when AAD authentication enabled." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "skuName": { + "type": "string", + "metadata": { + "description": "Required. The name of the sku, typically, tier + family + cores, e.g. Standard_D4s_v3." + } + }, + "tier": { + "type": "string", + "allowedValues": [ + "GeneralPurpose", + "Burstable", + "MemoryOptimized" + ], + "metadata": { + "description": "Required. The tier of the particular SKU. Tier must align with the \"skuName\" property. Example, tier cannot be \"Burstable\" if skuName is \"Standard_D4s_v3\"." + } + }, + "availabilityZone": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "1", + "2", + "3" + ], + "metadata": { + "description": "Optional. Availability zone information of the server. Default will have no preference set." + } + }, + "backupRetentionDays": { + "type": "int", + "defaultValue": 7, + "minValue": 7, + "maxValue": 35, + "metadata": { + "description": "Optional. Backup retention days for the server." + } + }, + "geoRedundantBackup": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. A value indicating whether Geo-Redundant backup is enabled on the server. Should be left disabled if 'cMKKeyName' is not empty." + } + }, + "storageSizeGB": { + "type": "int", + "defaultValue": 32, + "allowedValues": [ + 32, + 64, + 128, + 256, + 512, + 1024, + 2048, + 4096, + 8192, + 16384 + ], + "metadata": { + "description": "Optional. Max storage allowed for a server." + } + }, + "version": { + "type": "string", + "defaultValue": "15", + "allowedValues": [ + "11", + "12", + "13", + "14", + "15" + ], + "metadata": { + "description": "Optional. PostgreSQL Server version." + } + }, + "highAvailability": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "SameZone", + "ZoneRedundant" + ], + "metadata": { + "description": "Optional. The mode for high availability." + } + }, + "createMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Create", + "Default", + "PointInTimeRestore", + "Update" + ], + "metadata": { + "description": "Optional. The mode to create a new PostgreSQL server." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Conditional. The managed identity definition for this resource. Required if 'cMKKeyName' is not empty." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "maintenanceWindow": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Properties for the maintenence window. If provided, \"customWindow\" property must exist and set to \"Enabled\"." + } + }, + "pointInTimeUTC": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. Required if \"createMode\" is set to \"PointInTimeRestore\"." + } + }, + "sourceServerResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. Required if \"createMode\" is set to \"PointInTimeRestore\"." + } + }, + "delegatedSubnetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Delegated subnet arm resource ID. Used when the desired connectivity mode is \"Private Access\" - virtual network integration." + } + }, + "privateDnsZoneArmResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Private dns zone arm resource ID. Used when the desired connectivity mode is \"Private Access\" and required when \"delegatedSubnetResourceId\" is used. The Private DNS Zone must be lined to the Virtual Network referenced in \"delegatedSubnetResourceId\"." + } + }, + "firewallRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The firewall rules to create in the PostgreSQL flexible server." + } + }, + "databases": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The databases to create in the server." + } + }, + "configurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The configurations to create in the server." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "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'." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null()), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-07-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.dbforpostgresql-flexibleserver.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-07-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "flexibleServer": { + "type": "Microsoft.DBforPostgreSQL/flexibleServers", + "apiVersion": "2022-12-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('tier')]" + }, + "identity": "[variables('identity')]", + "properties": { + "administratorLogin": "[if(not(empty(parameters('administratorLogin'))), parameters('administratorLogin'), null())]", + "administratorLoginPassword": "[if(not(empty(parameters('administratorLoginPassword'))), parameters('administratorLoginPassword'), null())]", + "authConfig": { + "activeDirectoryAuth": "[parameters('activeDirectoryAuth')]", + "passwordAuth": "[parameters('passwordAuth')]", + "tenantId": "[if(not(empty(parameters('tenantId'))), parameters('tenantId'), null())]" + }, + "availabilityZone": "[parameters('availabilityZone')]", + "backup": { + "backupRetentionDays": "[parameters('backupRetentionDays')]", + "geoRedundantBackup": "[parameters('geoRedundantBackup')]" + }, + "createMode": "[parameters('createMode')]", + "dataEncryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('primaryKeyURI', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), reference('cMKKeyVault::cMKKey').keyUriWithVersion), 'primaryUserAssignedIdentityId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), 'type', 'AzureKeyVault'), null())]", + "highAvailability": { + "mode": "[parameters('highAvailability')]", + "standbyAvailabilityZone": "[if(equals(parameters('highAvailability'), 'SameZone'), parameters('availabilityZone'), null())]" + }, + "maintenanceWindow": "[if(not(empty(parameters('maintenanceWindow'))), createObject('customWindow', parameters('maintenanceWindow').customWindow, 'dayOfWeek', if(equals(parameters('maintenanceWindow').customWindow, 'Enabled'), parameters('maintenanceWindow').dayOfWeek, 0), 'startHour', if(equals(parameters('maintenanceWindow').customWindow, 'Enabled'), parameters('maintenanceWindow').startHour, 0), 'startMinute', if(equals(parameters('maintenanceWindow').customWindow, 'Enabled'), parameters('maintenanceWindow').startMinute, 0)), null())]", + "network": "[if(and(not(empty(parameters('delegatedSubnetResourceId'))), empty(parameters('firewallRules'))), createObject('delegatedSubnetResourceId', parameters('delegatedSubnetResourceId'), 'privateDnsZoneArmResourceId', parameters('privateDnsZoneArmResourceId')), null())]", + "pointInTimeUTC": "[if(equals(parameters('createMode'), 'PointInTimeRestore'), parameters('pointInTimeUTC'), null())]", + "sourceServerResourceId": "[if(equals(parameters('createMode'), 'PointInTimeRestore'), parameters('sourceServerResourceId'), null())]", + "storage": { + "storageSizeGB": "[parameters('storageSizeGB')]" + }, + "version": "[parameters('version')]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKUserAssignedIdentity" + ] + }, + "flexibleServer_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.DBforPostgreSQL/flexibleServers/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "flexibleServer" + ] + }, + "flexibleServer_roleAssignments": { + "copy": { + "name": "flexibleServer_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.DBforPostgreSQL/flexibleServers/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.DBforPostgreSQL/flexibleServers', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "flexibleServer" + ] + }, + "flexibleServer_diagnosticSettings": { + "copy": { + "name": "flexibleServer_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.DBforPostgreSQL/flexibleServers/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "metrics": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics', 'timeGrain', null(), 'enabled', true())))]", + "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'AllLogs', 'enabled', true())))]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "flexibleServer" + ] + }, + "flexibleServer_databases": { + "copy": { + "name": "flexibleServer_databases", + "count": "[length(parameters('databases'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PostgreSQL-DB-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('databases')[copyIndex()].name]" + }, + "flexibleServerName": { + "value": "[parameters('name')]" + }, + "collation": "[if(contains(parameters('databases')[copyIndex()], 'collation'), createObject('value', parameters('databases')[copyIndex()].collation), createObject('value', ''))]", + "charset": "[if(contains(parameters('databases')[copyIndex()], 'charset'), createObject('value', parameters('databases')[copyIndex()].charset), createObject('value', ''))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "2692846763140379246" + }, + "name": "DBforPostgreSQL Flexible Server Databases", + "description": "This module deploys a DBforPostgreSQL Flexible Server Database.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the database." + } + }, + "flexibleServerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment." + } + }, + "collation": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The collation of the database." + } + }, + "charset": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The charset of the database." + } + } + }, + "resources": [ + { + "type": "Microsoft.DBforPostgreSQL/flexibleServers/databases", + "apiVersion": "2022-12-01", + "name": "[format('{0}/{1}', parameters('flexibleServerName'), parameters('name'))]", + "properties": { + "collation": "[if(not(empty(parameters('collation'))), parameters('collation'), null())]", + "charset": "[if(not(empty(parameters('charset'))), parameters('charset'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed database." + }, + "value": "[resourceId('Microsoft.DBforPostgreSQL/flexibleServers/databases', parameters('flexibleServerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed database." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "flexibleServer" + ] + }, + "flexibleServer_firewallRules": { + "copy": { + "name": "flexibleServer_firewallRules", + "count": "[length(parameters('firewallRules'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PostgreSQL-FirewallRules-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('firewallRules')[copyIndex()].name]" + }, + "flexibleServerName": { + "value": "[parameters('name')]" + }, + "startIpAddress": { + "value": "[parameters('firewallRules')[copyIndex()].startIpAddress]" + }, + "endIpAddress": { + "value": "[parameters('firewallRules')[copyIndex()].endIpAddress]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "6933053371627105806" + }, + "name": "DBforPostgreSQL Flexible Server Firewall Rules", + "description": "This module deploys a DBforPostgreSQL Flexible Server Firewall Rule.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the PostgreSQL flexible server Firewall Rule." + } + }, + "startIpAddress": { + "type": "string", + "metadata": { + "description": "Required. The start IP address of the firewall rule. Must be IPv4 format. Use value '0.0.0.0' for all Azure-internal IP addresses." + } + }, + "endIpAddress": { + "type": "string", + "metadata": { + "description": "Required. The end IP address of the firewall rule. Must be IPv4 format. Must be greater than or equal to startIpAddress. Use value '0.0.0.0' for all Azure-internal IP addresses." + } + }, + "flexibleServerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment." + } + } + }, + "resources": [ + { + "type": "Microsoft.DBforPostgreSQL/flexibleServers/firewallRules", + "apiVersion": "2022-12-01", + "name": "[format('{0}/{1}', parameters('flexibleServerName'), parameters('name'))]", + "properties": { + "endIpAddress": "[parameters('endIpAddress')]", + "startIpAddress": "[parameters('startIpAddress')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed firewall rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed firewall rule." + }, + "value": "[resourceId('Microsoft.DBforPostgreSQL/flexibleServers/firewallRules', parameters('flexibleServerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed firewall rule." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "flexibleServer", + "flexibleServer_databases" + ] + }, + "flexibleServer_configurations": { + "copy": { + "name": "flexibleServer_configurations", + "count": "[length(parameters('configurations'))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PostgreSQL-Configurations-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('configurations')[copyIndex()].name]" + }, + "flexibleServerName": { + "value": "[parameters('name')]" + }, + "source": "[if(contains(parameters('configurations')[copyIndex()], 'source'), createObject('value', parameters('configurations')[copyIndex()].source), createObject('value', ''))]", + "value": "[if(contains(parameters('configurations')[copyIndex()], 'value'), createObject('value', parameters('configurations')[copyIndex()].value), createObject('value', ''))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "12646520601030472128" + }, + "name": "DBforPostgreSQL Flexible Server Configurations", + "description": "This module deploys a DBforPostgreSQL Flexible Server Configuration.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the configuration." + } + }, + "flexibleServerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment." + } + }, + "source": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Source of the configuration." + } + }, + "value": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Value of the configuration." + } + } + }, + "resources": [ + { + "type": "Microsoft.DBforPostgreSQL/flexibleServers/configurations", + "apiVersion": "2022-12-01", + "name": "[format('{0}/{1}', parameters('flexibleServerName'), parameters('name'))]", + "properties": { + "source": "[if(not(empty(parameters('source'))), parameters('source'), null())]", + "value": "[if(not(empty(parameters('value'))), parameters('value'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed configuration." + }, + "value": "[resourceId('Microsoft.DBforPostgreSQL/flexibleServers/configurations', parameters('flexibleServerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed configuration." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "flexibleServer", + "flexibleServer_firewallRules" + ] + }, + "flexibleServer_administrators": { + "copy": { + "name": "flexibleServer_administrators", + "count": "[length(parameters('administrators'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PostgreSQL-Administrators-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "flexibleServerName": { + "value": "[parameters('name')]" + }, + "objectId": { + "value": "[parameters('administrators')[copyIndex()].objectId]" + }, + "principalName": { + "value": "[parameters('administrators')[copyIndex()].principalName]" + }, + "principalType": { + "value": "[parameters('administrators')[copyIndex()].principalType]" + }, + "tenantId": "[if(contains(parameters('administrators')[copyIndex()], 'tenantId'), createObject('value', parameters('administrators')[copyIndex()].tenantId), createObject('value', tenant().tenantId))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "14731498034273397058" + }, + "name": "DBforPostgreSQL Flexible Server Administrators", + "description": "This module deploys a DBforPostgreSQL Flexible Server Administrator.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "flexibleServerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent PostgreSQL flexible server. Required if the template is used in a standalone deployment." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The objectId of the Active Directory administrator." + } + }, + "principalName": { + "type": "string", + "metadata": { + "description": "Required. Active Directory administrator principal name." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Group", + "ServicePrincipal", + "Unknown", + "User" + ], + "metadata": { + "description": "Required. The principal type used to represent the type of Active Directory Administrator." + } + }, + "tenantId": { + "type": "string", + "defaultValue": "[tenant().tenantId]", + "metadata": { + "description": "Optional. The tenantId of the Active Directory administrator." + } + } + }, + "resources": [ + { + "type": "Microsoft.DBforPostgreSQL/flexibleServers/administrators", + "apiVersion": "2022-12-01", + "name": "[format('{0}/{1}', parameters('flexibleServerName'), parameters('objectId'))]", + "properties": { + "principalName": "[parameters('principalName')]", + "principalType": "[parameters('principalType')]", + "tenantId": "[parameters('tenantId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed administrator." + }, + "value": "[parameters('objectId')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed administrator." + }, + "value": "[resourceId('Microsoft.DBforPostgreSQL/flexibleServers/administrators', parameters('flexibleServerName'), parameters('objectId'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed administrator." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "flexibleServer" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed PostgreSQL Flexible server." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed PostgreSQL Flexible server." + }, + "value": "[resourceId('Microsoft.DBforPostgreSQL/flexibleServers', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed PostgreSQL Flexible server." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('flexibleServer', '2022-12-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/defaults/main.test.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..b972cbcd5e --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,54 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-dbforpostgresql.flexibleservers-${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 = 'dfpsfsmin' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: location +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + administratorLogin: 'adminUserName' + administratorLoginPassword: password + skuName: 'Standard_B2s' + tier: 'Burstable' + } +}] diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/encr/dependencies.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/encr/dependencies.bicep new file mode 100644 index 0000000000..52be6351dc --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/encr/dependencies.bicep @@ -0,0 +1,58 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2023-07-01' = { + name: 'keyEncryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource keyPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault::key.id}-${location}-${managedIdentity.id}-Key-Reader-RoleAssignment') + scope: keyVault::key + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424') // Key Vault Crypto User + principalType: 'ServicePrincipal' + } +} + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The name of the created encryption key.') +output keyName string = keyVault::key.name diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/encr/main.test.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/encr/main.test.bicep new file mode 100644 index 0000000000..ac13e0f6e2 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/encr/main.test.bicep @@ -0,0 +1,83 @@ +targetScope = 'subscription' + +metadata name = 'Using Customer-Managed-Keys with User-Assigned identity' +metadata description = 'This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-dbforpostgresql.flexibleservers-${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 = 'dfpsfse' + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + // Adding base time to make the name unique as purge protection must be enabled (but may not be longer than 24 characters total) + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + administratorLogin: 'adminUserName' + administratorLoginPassword: password + skuName: 'Standard_D2s_v3' + tier: 'GeneralPurpose' + databases: [ + { + name: 'testdb1' + } + ] + customerManagedKey: { + keyName: nestedDependencies.outputs.keyName + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + userAssignedIdentityResourceId: nestedDependencies.outputs.managedIdentityResourceId + } + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + } +}] diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/private/dependencies.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/private/dependencies.bicep new file mode 100644 index 0000000000..ab0d44a734 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/private/dependencies.bicep @@ -0,0 +1,68 @@ +@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' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + delegations: [ + { + name: 'Microsoft.DBforPostgreSQL.flexibleServers' + properties: { + serviceName: 'Microsoft.DBforPostgreSQL/flexibleServers' + } + } + ] + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: '${split(virtualNetworkName, '-')[1]}.postgres.database.azure.com' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/private/main.test.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/private/main.test.bicep new file mode 100644 index 0000000000..727a1e8709 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/private/main.test.bicep @@ -0,0 +1,122 @@ +targetScope = 'subscription' + +metadata name = 'Private access' +metadata description = 'This instance deploys the module with private access only.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-dbforpostgresql.flexibleservers-${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 = 'dfpsfspvt' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: location + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + administratorLogin: 'adminUserName' + administratorLoginPassword: password + skuName: 'Standard_D2s_v3' + tier: 'GeneralPurpose' + configurations: [ + { + name: 'log_min_messages' + source: 'user-override' + value: 'INFO' + } + { + name: 'autovacuum_naptime' + source: 'user-override' + value: '80' + } + ] + databases: [ + { + charset: 'UTF8' + collation: 'en_US.utf8' + name: 'testdb1' + } + { + name: 'testdb2' + } + ] + delegatedSubnetResourceId: nestedDependencies.outputs.subnetResourceId + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + geoRedundantBackup: 'Enabled' + privateDnsZoneArmResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +}] diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/dependencies.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/dependencies.bicep new file mode 100644 index 0000000000..e8cc3c805a --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/dependencies.bicep @@ -0,0 +1,19 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The client ID of the created Managed Identity.') +output managedIdentityClientId string = managedIdentity.properties.clientId + +@description('The name of the created Managed Identity.') +output managedIdentityName string = managedIdentity.name diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/main.test.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/main.test.bicep new file mode 100644 index 0000000000..48bd268514 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/main.test.bicep @@ -0,0 +1,137 @@ +targetScope = 'subscription' + +metadata name = 'Public access' +metadata description = 'This instance deploys the module with public access.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-dbforpostgresql.flexibleservers-${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 = 'dfpsfsp' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: location + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + administrators: [ + { + objectId: nestedDependencies.outputs.managedIdentityClientId + principalName: nestedDependencies.outputs.managedIdentityName + principalType: 'ServicePrincipal' + } + ] + skuName: 'Standard_D2s_v3' + tier: 'GeneralPurpose' + availabilityZone: '1' + backupRetentionDays: 20 + configurations: [ + { + name: 'log_min_messages' + source: 'user-override' + value: 'INFO' + } + ] + databases: [ + { + charset: 'UTF8' + collation: 'en_US.utf8' + name: 'testdb1' + } + { + name: 'testdb2' + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + firewallRules: [ + { + endIpAddress: '0.0.0.0' + name: 'AllowAllWindowsAzureIps' + startIpAddress: '0.0.0.0' + } + { + endIpAddress: '10.10.10.10' + name: 'test-rule1' + startIpAddress: '10.10.10.1' + } + { + endIpAddress: '100.100.100.10' + name: 'test-rule2' + startIpAddress: '100.100.100.1' + } + ] + geoRedundantBackup: 'Disabled' + highAvailability: 'SameZone' + location: location + storageSizeGB: 1024 + version: '14' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +}] diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 0000000000..c62ca6138e --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,71 @@ +@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' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + delegations: [ + { + name: 'Microsoft.DBforPostgreSQL.flexibleServers' + properties: { + serviceName: 'Microsoft.DBforPostgreSQL/flexibleServers' + } + } + ] + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: '${split(virtualNetworkName, '-')[1]}.postgres.database.azure.com' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The client ID of the created Managed Identity.') +output managedIdentityClientId string = managedIdentity.properties.clientId + +@description('The name of the created Managed Identity.') +output managedIdentityName string = managedIdentity.name diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/waf-aligned/main.test.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..e0bebc0c41 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,119 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +// e.g., for a module 'network/private-endpoint' you could use 'dep-dev-network.privateendpoints-${serviceShort}-rg' +param resourceGroupName string = 'dep-${namePrefix}-dbforpostgresql.flexibleservers-${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.') +// e.g., for a module 'network/private-endpoint' you could use 'npe' as a prefix and then 'waf' as a suffix for the waf-aligned test +param serviceShort string = 'dfpsfswaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: location + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + administrators: [ + { + objectId: nestedDependencies.outputs.managedIdentityClientId + principalName: nestedDependencies.outputs.managedIdentityName + principalType: 'ServicePrincipal' + } + ] + skuName: 'Standard_D2s_v3' + tier: 'GeneralPurpose' + configurations: [ + { + name: 'log_min_messages' + source: 'user-override' + value: 'INFO' + } + { + name: 'autovacuum_naptime' + source: 'user-override' + value: '80' + } + ] + databases: [ + { + charset: 'UTF8' + collation: 'en_US.utf8' + name: 'testdb1' + } + { + name: 'testdb2' + } + ] + delegatedSubnetResourceId: nestedDependencies.outputs.subnetResourceId + diagnosticSettings: [ + { + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + geoRedundantBackup: 'Enabled' + privateDnsZoneArmResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +}] diff --git a/avm/res/db-for-postgre-sql/flexible-server/version.json b/avm/res/db-for-postgre-sql/flexible-server/version.json new file mode 100644 index 0000000000..83083db694 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file From 4a393e66f911750a714d1508119f82203ca211d8 Mon Sep 17 00:00:00 2001 From: Kris Baranek Date: Fri, 24 Nov 2023 16:55:40 +0100 Subject: [PATCH 02/22] fix: removed availablityZone from `avm/res/db-for-postgre-sql/flexible-server` (#671) ## Description Removed availablityZone parameter from the `public` test case due to Azure Region capacity restrictions. --- avm/res/db-for-postgre-sql/flexible-server/README.md | 4 ---- .../flexible-server/tests/e2e/public/main.test.bicep | 1 - 2 files changed, 5 deletions(-) diff --git a/avm/res/db-for-postgre-sql/flexible-server/README.md b/avm/res/db-for-postgre-sql/flexible-server/README.md index 4b1ab8afb8..c37d771a28 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/README.md +++ b/avm/res/db-for-postgre-sql/flexible-server/README.md @@ -392,7 +392,6 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server: Date: Fri, 24 Nov 2023 19:11:11 +0100 Subject: [PATCH 03/22] fix: quotes update in `avm/res/db-for-postgre-sql/flexible-server` (#672) ## Description Minor update to trigger the publishing. ## Pipeline references | Pipeline | | - | | [![avm.res.db-for-postgre-sql.flexible-server](https://github.com/krbar/bicep-registry-modules/actions/workflows/avm.res.db-for-postgre-sql.flexible-server.yml/badge.svg?branch=users%2Fkrbar%2FpostgreModify)](https://github.com/krbar/bicep-registry-modules/actions/workflows/avm.res.db-for-postgre-sql.flexible-server.yml)
**Note**: due to region limitation for the test subscriptions which is not allowed to deploy this resource in the region `West Europe`, the test have been performed in `North Europe`. The last commit (changing the region back to `West Europe`) was not included in the test. | --- .../flexible-server/README.md | 24 +++++++++---------- .../flexible-server/main.bicep | 12 +++++----- .../flexible-server/main.json | 14 +++++------ 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/avm/res/db-for-postgre-sql/flexible-server/README.md b/avm/res/db-for-postgre-sql/flexible-server/README.md index c37d771a28..7581109ac8 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/README.md +++ b/avm/res/db-for-postgre-sql/flexible-server/README.md @@ -746,15 +746,15 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server: Date: Sat, 25 Nov 2023 16:13:15 +0100 Subject: [PATCH 04/22] feat: new module eventgrid /topic migrated from CARML to AVM (#652) ## Description New module migrated from CARML to AVM [![avm.res.event-grid.topic](https://github.com/fabmas/bicep-registry-modules/actions/workflows/avm.res.event-grid.topic.yml/badge.svg?branch=eg%2Ftopic)](https://github.com/fabmas/bicep-registry-modules/actions/workflows/avm.res.event-grid.topic.yml) --------- Co-authored-by: Fabio Masciotra Co-authored-by: Alexander Sehr --- .../workflows/avm.res.event-grid.topic.yml | 81 + avm/res/event-grid/topic/README.md | 1147 ++++++++++++++ .../topic/event-subscription/README.md | 136 ++ .../topic/event-subscription/main.bicep | 76 + .../topic/event-subscription/main.json | 144 ++ avm/res/event-grid/topic/main.bicep | 350 +++++ avm/res/event-grid/topic/main.json | 1360 +++++++++++++++++ .../topic/tests/e2e/defaults/main.test.bicep | 45 + .../topic/tests/e2e/max/dependencies.bicep | 89 ++ .../topic/tests/e2e/max/main.test.bicep | 167 ++ .../topic/tests/e2e/pe/dependencies.bicep | 49 + .../topic/tests/e2e/pe/main.test.bicep | 74 + .../tests/e2e/waf-aligned/dependencies.bicep | 89 ++ .../tests/e2e/waf-aligned/main.test.bicep | 133 ++ avm/res/event-grid/topic/version.json | 7 + 15 files changed, 3947 insertions(+) create mode 100644 .github/workflows/avm.res.event-grid.topic.yml create mode 100644 avm/res/event-grid/topic/README.md create mode 100644 avm/res/event-grid/topic/event-subscription/README.md create mode 100644 avm/res/event-grid/topic/event-subscription/main.bicep create mode 100644 avm/res/event-grid/topic/event-subscription/main.json create mode 100644 avm/res/event-grid/topic/main.bicep create mode 100644 avm/res/event-grid/topic/main.json create mode 100644 avm/res/event-grid/topic/tests/e2e/defaults/main.test.bicep create mode 100644 avm/res/event-grid/topic/tests/e2e/max/dependencies.bicep create mode 100644 avm/res/event-grid/topic/tests/e2e/max/main.test.bicep create mode 100644 avm/res/event-grid/topic/tests/e2e/pe/dependencies.bicep create mode 100644 avm/res/event-grid/topic/tests/e2e/pe/main.test.bicep create mode 100644 avm/res/event-grid/topic/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/res/event-grid/topic/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/res/event-grid/topic/version.json diff --git a/.github/workflows/avm.res.event-grid.topic.yml b/.github/workflows/avm.res.event-grid.topic.yml new file mode 100644 index 0000000000..3eb80d2bac --- /dev/null +++ b/.github/workflows/avm.res.event-grid.topic.yml @@ -0,0 +1,81 @@ +name: "avm.res.event-grid.topic" + +on: + schedule: + - cron: "0 12 1/15 * *" # Bi-Weekly Test (on 1st & 15th of month) + 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 + + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.event-grid.topic.yml" + - "avm/res/event-grid/topic/**" + - "avm/utilities/pipelines/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/event-grid/topic" + workflowPath: ".github/workflows/avm.res.event-grid.topic.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-20.04 + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get parameter file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Module" + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/res/event-grid/topic/README.md b/avm/res/event-grid/topic/README.md new file mode 100644 index 0000000000..67758a5ec4 --- /dev/null +++ b/avm/res/event-grid/topic/README.md @@ -0,0 +1,1147 @@ +# Event Grid Topics `[Microsoft.EventGrid/topics]` + +This module deploys an Event Grid Topic. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| 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/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.EventGrid/topics` | [2021-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.EventGrid/2021-06-01-preview/topics) | +| `Microsoft.EventGrid/topics/eventSubscriptions` | [2022-06-15](https://learn.microsoft.com/en-us/azure/templates/Microsoft.EventGrid/2022-06-15/topics/eventSubscriptions) | +| `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` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/event-grid/topic:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [Using private endpoint](#example-3-using-private-endpoint) +- [WAF-aligned](#example-4-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module topic 'br/public:avm/res/event-grid/topic:' = { + name: '${uniqueString(deployment().name, location)}-test-egtmin' + params: { + // Required parameters + name: 'egtmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +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": "egtmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module topic 'br/public:avm/res/event-grid/topic:' = { + name: '${uniqueString(deployment().name, location)}-test-egtmax' + params: { + // Required parameters + name: 'egtmax001' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + eventSubscriptions: [ + { + destination: { + endpointType: 'StorageQueue' + properties: { + queueMessageTimeToLiveInSeconds: 86400 + queueName: '' + resourceId: '' + } + } + eventDeliverySchema: 'CloudEventSchemaV1_0' + expirationTimeUtc: '2099-01-01T11:00:21.715Z' + filter: { + enableAdvancedFilteringOnArrays: true + isSubjectCaseSensitive: false + } + name: 'egtmax001' + retryPolicy: { + eventTimeToLive: '120' + maxDeliveryAttempts: 10 + } + } + ] + inboundIpRules: [ + { + action: 'Allow' + ipMask: '40.74.28.0/23' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + '' + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + service: 'topic' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +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": "egtmax001" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "eventSubscriptions": { + "value": [ + { + "destination": { + "endpointType": "StorageQueue", + "properties": { + "queueMessageTimeToLiveInSeconds": 86400, + "queueName": "", + "resourceId": "" + } + }, + "eventDeliverySchema": "CloudEventSchemaV1_0", + "expirationTimeUtc": "2099-01-01T11:00:21.715Z", + "filter": { + "enableAdvancedFilteringOnArrays": true, + "isSubjectCaseSensitive": false + }, + "name": "egtmax001", + "retryPolicy": { + "eventTimeToLive": "120", + "maxDeliveryAttempts": 10 + } + } + ] + }, + "inboundIpRules": { + "value": [ + { + "action": "Allow", + "ipMask": "40.74.28.0/23" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneResourceIds": [ + "" + ], + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "service": "topic", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + ] + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +### Example 3: _Using private endpoint_ + +This instance deploys the module with the private endpoint. + + +

+ +via Bicep module + +```bicep +module topic 'br/public:avm/res/event-grid/topic:' = { + name: '${uniqueString(deployment().name, location)}-test-egtpe' + params: { + // Required parameters + name: 'egtpe001' + // Non-required parameters + location: '' + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +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": "egtpe001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneResourceIds": [ + "" + ], + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +### Example 4: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module topic 'br/public:avm/res/event-grid/topic:' = { + name: '${uniqueString(deployment().name, location)}-test-egtwaf' + params: { + // Required parameters + name: 'egtwaf001' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + eventSubscriptions: [ + { + destination: { + endpointType: 'StorageQueue' + properties: { + queueMessageTimeToLiveInSeconds: 86400 + queueName: '' + resourceId: '' + } + } + eventDeliverySchema: 'CloudEventSchemaV1_0' + expirationTimeUtc: '2099-01-01T11:00:21.715Z' + filter: { + enableAdvancedFilteringOnArrays: true + isSubjectCaseSensitive: false + } + name: 'egtwaf001' + retryPolicy: { + eventTimeToLive: '120' + maxDeliveryAttempts: 10 + } + } + ] + inboundIpRules: [] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + '' + ] + service: 'topic' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +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": "egtwaf001" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "eventSubscriptions": { + "value": [ + { + "destination": { + "endpointType": "StorageQueue", + "properties": { + "queueMessageTimeToLiveInSeconds": 86400, + "queueName": "", + "resourceId": "" + } + }, + "eventDeliverySchema": "CloudEventSchemaV1_0", + "expirationTimeUtc": "2099-01-01T11:00:21.715Z", + "filter": { + "enableAdvancedFilteringOnArrays": true, + "isSubjectCaseSensitive": false + }, + "name": "egtwaf001", + "retryPolicy": { + "eventTimeToLive": "120", + "maxDeliveryAttempts": 10 + } + } + ] + }, + "inboundIpRules": { + "value": [] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneResourceIds": [ + "" + ], + "service": "topic", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the Event Grid Topic. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`disableLocalAuth`](#parameter-disablelocalauth) | bool | Allow only Azure AD authentication. Should be enabled for security reasons. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`eventSubscriptions`](#parameter-eventsubscriptions) | array | Event subscriptions to deploy. | +| [`inboundIpRules`](#parameter-inboundiprules) | array | This can be used to restrict traffic from specific IPs instead of all IPs. Note: These are considered only if PublicNetworkAccess is enabled. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | +| [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | 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 inboundIpRules are not set. | +| [`roleAssignments`](#parameter-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'. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. +- Required: No +- Type: array + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | No | string | 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. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | No | string | 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. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | No | string | Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | No | array | Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | No | string | Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | No | array | Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. | +| [`name`](#parameter-diagnosticsettingsname) | No | string | Optional. The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | No | string | 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. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | No | string | 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. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +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. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +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. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: `[AzureDiagnostics, Dedicated]` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. + +- Required: No +- Type: array + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | No | string | Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | No | string | Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to 'AllLogs' to collect all logs. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to 'AllLogs' to collect all logs. + +- Required: No +- Type: string + + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. + +- Required: No +- Type: array + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | Yes | string | Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to 'AllMetrics' to collect all metrics. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to 'AllMetrics' to collect all metrics. + +- Required: Yes +- Type: string + + +### Parameter: `diagnosticSettings.name` + +Optional. The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +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. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +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. + +- Required: No +- Type: string + +### Parameter: `disableLocalAuth` + +Allow only Azure AD authentication. Should be enabled for security reasons. +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `eventSubscriptions` + +Event subscriptions to deploy. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `inboundIpRules` + +This can be used to restrict traffic from specific IPs instead of all IPs. Note: These are considered only if PublicNetworkAccess is enabled. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `location` + +Location for all Resources. +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. +- Required: No +- Type: object + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`kind`](#parameter-lockkind) | No | string | Optional. Specify the type of lock. | +| [`name`](#parameter-lockname) | No | string | Optional. Specify the name of lock. | + +### Parameter: `lock.kind` + +Optional. Specify the type of lock. + +- Required: No +- Type: string +- Allowed: `[CanNotDelete, None, ReadOnly]` + +### Parameter: `lock.name` + +Optional. Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. +- Required: No +- Type: object + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`systemAssigned`](#parameter-managedidentitiessystemassigned) | No | bool | Optional. Enables system assigned managed identity on the resource. | +| [`userAssignedResourcesIds`](#parameter-managedidentitiesuserassignedresourcesids) | No | array | Optional. The resource ID(s) to assign to the resource. | + +### Parameter: `managedIdentities.systemAssigned` + +Optional. Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + +### Parameter: `managedIdentities.userAssignedResourcesIds` + +Optional. The resource ID(s) to assign to the resource. + +- Required: No +- Type: array + +### Parameter: `name` + +The name of the Event Grid Topic. +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints` + +Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. +- Required: No +- Type: array + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`applicationSecurityGroupResourceIds`](#parameter-privateendpointsapplicationsecuritygroupresourceids) | No | array | Optional. Application security groups in which the private endpoint IP configuration is included. | +| [`customDnsConfigs`](#parameter-privateendpointscustomdnsconfigs) | No | array | Optional. Custom DNS configurations. | +| [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | No | string | Optional. The custom name of the network interface attached to the private endpoint. | +| [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | No | bool | Optional. Enable/Disable usage telemetry for module. | +| [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | No | array | Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`location`](#parameter-privateendpointslocation) | No | string | Optional. The location to deploy the private endpoint to. | +| [`lock`](#parameter-privateendpointslock) | No | object | Optional. Specify the type of lock. | +| [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | No | array | Optional. Manual PrivateLink Service Connections. | +| [`name`](#parameter-privateendpointsname) | No | string | Optional. The name of the private endpoint. | +| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | No | string | Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. | +| [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | No | array | Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | array | 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'. | +| [`service`](#parameter-privateendpointsservice) | No | string | Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | +| [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | Yes | string | Required. Resource ID of the subnet where the endpoint needs to be created. | +| [`tags`](#parameter-privateendpointstags) | No | object | Optional. Tags to be applied on all resources/resource groups in this deployment. | + +### Parameter: `privateEndpoints.applicationSecurityGroupResourceIds` + +Optional. Application security groups in which the private endpoint IP configuration is included. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints.customDnsConfigs` + +Optional. Custom DNS configurations. + +- Required: No +- Type: array + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | No | string | Required. Fqdn that resolves to private endpoint ip address. | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | Yes | array | Required. A list of private ip addresses of the private endpoint. | + +### Parameter: `privateEndpoints.customDnsConfigs.fqdn` + +Required. Fqdn that resolves to private endpoint ip address. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` + +Required. A list of private ip addresses of the private endpoint. + +- Required: Yes +- Type: array + + +### Parameter: `privateEndpoints.customNetworkInterfaceName` + +Optional. The custom name of the network interface attached to the private endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.enableTelemetry` + +Optional. Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool + +### Parameter: `privateEndpoints.ipConfigurations` + +Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. + +- Required: No +- Type: array + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`name`](#parameter-privateendpointsipconfigurationsname) | Yes | string | Required. The name of the resource that is unique within a resource group. | +| [`properties`](#parameter-privateendpointsipconfigurationsproperties) | Yes | object | Required. Properties of private endpoint IP configurations. | + +### Parameter: `privateEndpoints.ipConfigurations.name` + +Required. The name of the resource that is unique within a resource group. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties` + +Required. Properties of private endpoint IP configurations. + +- Required: Yes +- Type: object + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | Yes | string | Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. | +| [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | Yes | string | Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | Yes | string | Required. A private ip address obtained from the private endpoint's subnet. | + +### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` + +Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties.memberName` + +Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` + +Required. A private ip address obtained from the private endpoint's subnet. + +- Required: Yes +- Type: string + + + +### Parameter: `privateEndpoints.location` + +Optional. The location to deploy the private endpoint to. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.lock` + +Optional. Specify the type of lock. + +- Required: No +- Type: object + +### Parameter: `privateEndpoints.manualPrivateLinkServiceConnections` + +Optional. Manual PrivateLink Service Connections. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints.name` + +Optional. The name of the private endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroupName` + +Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneResourceIds` + +Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints.roleAssignments` + +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'. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints.service` + +Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.subnetResourceId` + +Required. Resource ID of the subnet where the endpoint needs to be created. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.tags` + +Optional. Tags to be applied on all resources/resource groups in this deployment. + +- Required: No +- Type: object + +### Parameter: `publicNetworkAccess` + +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 inboundIpRules are not set. +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `roleAssignments` + +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'. +- Required: No +- Type: array + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`condition`](#parameter-roleassignmentscondition) | No | string | 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" | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | No | string | Optional. Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | No | string | Optional. The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | +| [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | + +### Parameter: `roleAssignments.condition` + +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" + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Optional. Version of the condition. + +- Required: No +- Type: string +- Allowed: `[2.0]` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +Optional. The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +Optional. The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalId` + +Required. The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.principalType` + +Optional. The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: `[Device, ForeignGroup, Group, ServicePrincipal, User]` + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. + +- Required: Yes +- Type: string + +### Parameter: `tags` + +Tags of the resource. +- Required: No +- Type: object + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the event grid topic. | +| `resourceGroupName` | string | The name of the resource group the event grid topic was deployed into. | +| `resourceId` | string | The resource ID of the event grid topic. | +| `systemAssignedMIPrincipalId` | 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 | +| :-- | :-- | +| `br/public:avm-res-network-privateendpoint:0.1.1` | Remote reference | diff --git a/avm/res/event-grid/topic/event-subscription/README.md b/avm/res/event-grid/topic/event-subscription/README.md new file mode 100644 index 0000000000..da0c521476 --- /dev/null +++ b/avm/res/event-grid/topic/event-subscription/README.md @@ -0,0 +1,136 @@ +# EventGrid Topic Event Subscriptions `[Microsoft.EventGrid/topics/eventSubscriptions]` + +This module deploys an Event Grid Topic Event Subscription. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.EventGrid/topics/eventSubscriptions` | [2022-06-15](https://learn.microsoft.com/en-us/azure/templates/Microsoft.EventGrid/2022-06-15/topics/eventSubscriptions) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`destination`](#parameter-destination) | object | The destination for the event subscription. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#eventsubscriptiondestination-objects for more information). | +| [`name`](#parameter-name) | string | The name of the Event Subscription. | +| [`topicName`](#parameter-topicname) | string | Name of the Event Grid Topic. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`deadLetterDestination`](#parameter-deadletterdestination) | object | Dead Letter Destination. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#deadletterdestination-objects for more information). | +| [`deadLetterWithResourceIdentity`](#parameter-deadletterwithresourceidentity) | object | Dead Letter with Resource Identity Configuration. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#deadletterwithresourceidentity-objects for more information). | +| [`deliveryWithResourceIdentity`](#parameter-deliverywithresourceidentity) | object | Delivery with Resource Identity Configuration. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#deliverywithresourceidentity-objects for more information). | +| [`eventDeliverySchema`](#parameter-eventdeliveryschema) | string | The event delivery schema for the event subscription. | +| [`expirationTimeUtc`](#parameter-expirationtimeutc) | string | The expiration time for the event subscription. Format is ISO-8601 (yyyy-MM-ddTHH:mm:ssZ). | +| [`filter`](#parameter-filter) | object | The filter for the event subscription. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#eventsubscriptionfilter for more information). | +| [`labels`](#parameter-labels) | array | The list of user defined labels. | +| [`retryPolicy`](#parameter-retrypolicy) | object | The retry policy for events. This can be used to configure the TTL and maximum number of delivery attempts and time to live for events. | + +### Parameter: `deadLetterDestination` + +Dead Letter Destination. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#deadletterdestination-objects for more information). +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `deadLetterWithResourceIdentity` + +Dead Letter with Resource Identity Configuration. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#deadletterwithresourceidentity-objects for more information). +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `deliveryWithResourceIdentity` + +Delivery with Resource Identity Configuration. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#deliverywithresourceidentity-objects for more information). +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `destination` + +The destination for the event subscription. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#eventsubscriptiondestination-objects for more information). +- Required: Yes +- Type: object + +### Parameter: `eventDeliverySchema` + +The event delivery schema for the event subscription. +- Required: No +- Type: string +- Default: `'EventGridSchema'` +- Allowed: + ```Bicep + [ + 'CloudEventSchemaV1_0' + 'CustomInputSchema' + 'EventGridEvent' + 'EventGridSchema' + ] + ``` + +### Parameter: `expirationTimeUtc` + +The expiration time for the event subscription. Format is ISO-8601 (yyyy-MM-ddTHH:mm:ssZ). +- Required: No +- Type: string +- Default: `''` + +### Parameter: `filter` + +The filter for the event subscription. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#eventsubscriptionfilter for more information). +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `labels` + +The list of user defined labels. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `name` + +The name of the Event Subscription. +- Required: Yes +- Type: string + +### Parameter: `retryPolicy` + +The retry policy for events. This can be used to configure the TTL and maximum number of delivery attempts and time to live for events. +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `topicName` + +Name of the Event Grid Topic. +- Required: Yes +- Type: string + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the event subscription. | +| `resourceGroupName` | string | The name of the resource group the event subscription was deployed into. | +| `resourceId` | string | The resource ID of the event subscription. | + +## Cross-referenced modules + +_None_ diff --git a/avm/res/event-grid/topic/event-subscription/main.bicep b/avm/res/event-grid/topic/event-subscription/main.bicep new file mode 100644 index 0000000000..367997420c --- /dev/null +++ b/avm/res/event-grid/topic/event-subscription/main.bicep @@ -0,0 +1,76 @@ +metadata name = 'EventGrid Topic Event Subscriptions' +metadata description = 'This module deploys an Event Grid Topic Event Subscription.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the Event Subscription.') +param name string + +@description('Required. Name of the Event Grid Topic.') +param topicName string + +@description('Optional. Dead Letter Destination. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#deadletterdestination-objects for more information).') +param deadLetterDestination object = {} + +@description('Optional. Dead Letter with Resource Identity Configuration. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#deadletterwithresourceidentity-objects for more information).') +param deadLetterWithResourceIdentity object = {} + +@description('Optional. Delivery with Resource Identity Configuration. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#deliverywithresourceidentity-objects for more information).') +param deliveryWithResourceIdentity object = {} + +@description('Required. The destination for the event subscription. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#eventsubscriptiondestination-objects for more information).') +param destination object + +@description('Optional. The event delivery schema for the event subscription.') +@allowed( + [ + 'CloudEventSchemaV1_0' + 'CustomInputSchema' + 'EventGridSchema' + 'EventGridEvent' + ] +) +param eventDeliverySchema string = 'EventGridSchema' + +@description('Optional. The expiration time for the event subscription. Format is ISO-8601 (yyyy-MM-ddTHH:mm:ssZ).') +param expirationTimeUtc string = '' + +@description('Optional. The filter for the event subscription. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#eventsubscriptionfilter for more information).') +param filter object = {} + +@description('Optional. The list of user defined labels.') +param labels array = [] + +@description('Optional. The retry policy for events. This can be used to configure the TTL and maximum number of delivery attempts and time to live for events.') +param retryPolicy object = {} + +resource topic 'Microsoft.EventGrid/topics@2022-06-15' existing = { + name: topicName +} + +resource eventSubscription 'Microsoft.EventGrid/topics/eventSubscriptions@2022-06-15' = { + name: name + parent: topic + properties: { + deadLetterDestination: !empty(deadLetterDestination) ? deadLetterDestination : null + deadLetterWithResourceIdentity: !empty(deadLetterWithResourceIdentity) ? deadLetterWithResourceIdentity : null + deliveryWithResourceIdentity: !empty(deliveryWithResourceIdentity) ? deliveryWithResourceIdentity : null + destination: destination + eventDeliverySchema: eventDeliverySchema + expirationTimeUtc: !empty(expirationTimeUtc) ? expirationTimeUtc : '' + filter: !empty(filter) ? filter : {} + labels: !empty(labels) ? labels : [] + retryPolicy: !empty(retryPolicy) ? retryPolicy : null + } +} + +@description('The name of the event subscription.') +output name string = eventSubscription.name + +@description('The resource ID of the event subscription.') +output resourceId string = eventSubscription.id + +@description('The name of the resource group the event subscription was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = topic.location diff --git a/avm/res/event-grid/topic/event-subscription/main.json b/avm/res/event-grid/topic/event-subscription/main.json new file mode 100644 index 0000000000..ab8a268266 --- /dev/null +++ b/avm/res/event-grid/topic/event-subscription/main.json @@ -0,0 +1,144 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "9051512137045314881" + }, + "name": "EventGrid Topic Event Subscriptions", + "description": "This module deploys an Event Grid Topic Event Subscription.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Event Subscription." + } + }, + "topicName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Event Grid Topic." + } + }, + "deadLetterDestination": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Dead Letter Destination. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#deadletterdestination-objects for more information)." + } + }, + "deadLetterWithResourceIdentity": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Dead Letter with Resource Identity Configuration. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#deadletterwithresourceidentity-objects for more information)." + } + }, + "deliveryWithResourceIdentity": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Delivery with Resource Identity Configuration. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#deliverywithresourceidentity-objects for more information)." + } + }, + "destination": { + "type": "object", + "metadata": { + "description": "Required. The destination for the event subscription. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#eventsubscriptiondestination-objects for more information)." + } + }, + "eventDeliverySchema": { + "type": "string", + "defaultValue": "EventGridSchema", + "allowedValues": [ + "CloudEventSchemaV1_0", + "CustomInputSchema", + "EventGridSchema", + "EventGridEvent" + ], + "metadata": { + "description": "Optional. The event delivery schema for the event subscription." + } + }, + "expirationTimeUtc": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The expiration time for the event subscription. Format is ISO-8601 (yyyy-MM-ddTHH:mm:ssZ)." + } + }, + "filter": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The filter for the event subscription. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#eventsubscriptionfilter for more information)." + } + }, + "labels": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The list of user defined labels." + } + }, + "retryPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The retry policy for events. This can be used to configure the TTL and maximum number of delivery attempts and time to live for events." + } + } + }, + "resources": [ + { + "type": "Microsoft.EventGrid/topics/eventSubscriptions", + "apiVersion": "2022-06-15", + "name": "[format('{0}/{1}', parameters('topicName'), parameters('name'))]", + "properties": { + "deadLetterDestination": "[if(not(empty(parameters('deadLetterDestination'))), parameters('deadLetterDestination'), null())]", + "deadLetterWithResourceIdentity": "[if(not(empty(parameters('deadLetterWithResourceIdentity'))), parameters('deadLetterWithResourceIdentity'), null())]", + "deliveryWithResourceIdentity": "[if(not(empty(parameters('deliveryWithResourceIdentity'))), parameters('deliveryWithResourceIdentity'), null())]", + "destination": "[parameters('destination')]", + "eventDeliverySchema": "[parameters('eventDeliverySchema')]", + "expirationTimeUtc": "[if(not(empty(parameters('expirationTimeUtc'))), parameters('expirationTimeUtc'), '')]", + "filter": "[if(not(empty(parameters('filter'))), parameters('filter'), createObject())]", + "labels": "[if(not(empty(parameters('labels'))), parameters('labels'), createArray())]", + "retryPolicy": "[if(not(empty(parameters('retryPolicy'))), parameters('retryPolicy'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the event subscription." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the event subscription." + }, + "value": "[resourceId('Microsoft.EventGrid/topics/eventSubscriptions', parameters('topicName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the event subscription was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference(resourceId('Microsoft.EventGrid/topics', parameters('topicName')), '2022-06-15', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/res/event-grid/topic/main.bicep b/avm/res/event-grid/topic/main.bicep new file mode 100644 index 0000000000..8f38a3ec89 --- /dev/null +++ b/avm/res/event-grid/topic/main.bicep @@ -0,0 +1,350 @@ +metadata name = 'Event Grid Topics' +metadata description = 'This module deploys an Event Grid Topic.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the Event Grid Topic.') +param name string + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@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 and inboundIpRules are not set.') +@allowed([ + '' + 'Enabled' + 'Disabled' +]) +param publicNetworkAccess string = '' + +@description('Optional. This can be used to restrict traffic from specific IPs instead of all IPs. Note: These are considered only if PublicNetworkAccess is enabled.') +param inboundIpRules array = [] + +@description('Optional. Event subscriptions to deploy.') +param eventSubscriptions array = [] + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointType + +@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 roleAssignmentType + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType + +@description('Optional. Allow only Azure AD authentication. Should be enabled for security reasons.') +param disableLocalAuth bool = true + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var formattedUserAssignedIdentities = reduce(map((managedIdentities.?userAssignedResourcesIds ?? []), (id) => { '${id}': {} }), {}, (cur, next) => union(cur, next)) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) ? { + type: (managedIdentities.?systemAssigned ?? false) ? (!empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null) + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null +} : null + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'EventGrid Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1e241071-0855-49ea-94dc-649edcd759de') + 'EventGrid Data Sender': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd5a91429-5739-47e2-a06b-3470a27159e7') + 'EventGrid EventSubscription Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '428e0ff0-5e57-4d9c-a221-2c70d0e0a443') + 'EventGrid EventSubscription Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2414bbcf-6497-4faf-8c65-045460748405') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + '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 avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: take('46d3xbcp.res.eventgrid-topic.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', 64) + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource topic 'Microsoft.EventGrid/topics@2021-06-01-preview' = { + name: name + location: location + identity: identity + tags: tags + properties: { + publicNetworkAccess: !empty(publicNetworkAccess) ? any(publicNetworkAccess) : (!empty(privateEndpoints) && empty(inboundIpRules) ? 'Disabled' : null) + inboundIpRules: (empty(inboundIpRules) ? null : inboundIpRules) + disableLocalAuth: disableLocalAuth + } +} + +// Event subscriptions +module topics_eventSubscriptions 'event-subscription/main.bicep' = [for (eventSubscription, index) in eventSubscriptions: { + name: '${uniqueString(deployment().name, location)}-EventGrid-Topics-EventSubscriptions-${index}' + params: { + destination: eventSubscription.destination + topicName: topic.name + name: eventSubscription.name + deadLetterDestination: contains(eventSubscriptions, 'deadLetterDestination') ? eventSubscription.deadLetterDestination : {} + deadLetterWithResourceIdentity: contains(eventSubscriptions, 'deadLetterWithResourceIdentity') ? eventSubscription.deadLetterWithResourceIdentity : {} + deliveryWithResourceIdentity: contains(eventSubscriptions, 'deliveryWithResourceIdentity') ? eventSubscription.deliveryWithResourceIdentity : {} + eventDeliverySchema: contains(eventSubscriptions, 'eventDeliverySchema') ? eventSubscription.eventDeliverySchema : 'EventGridSchema' + expirationTimeUtc: contains(eventSubscriptions, 'expirationTimeUtc') ? eventSubscription.expirationTimeUtc : '' + filter: contains(eventSubscriptions, 'filter') ? eventSubscription.filter : {} + labels: contains(eventSubscriptions, 'labels') ? eventSubscription.labels : [] + retryPolicy: contains(eventSubscriptions, 'retryPolicy') ? eventSubscription.retryPolicy : {} + } +}] + +resource topic_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' ? 'Cannot delete resource or child resources.' : 'Cannot delete or modify the resource or child resources.' + } + scope: topic +} + +resource topic_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: diagnosticSetting.?metricCategories ?? [ + { + category: 'AllMetrics' + timeGrain: null + enabled: true + } + ] + logs: diagnosticSetting.?logCategoriesAndGroups ?? [ + { + categoryGroup: 'AllLogs' + enabled: true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: topic +}] + +module topic_privateEndpoints 'br/public:avm-res-network-privateendpoint:0.1.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-topic-PrivateEndpoint-${index}' + params: { + groupIds: [ + privateEndpoint.?service ?? 'topic' + ] + name: privateEndpoint.?name ?? 'pep-${last(split(topic.id, '/'))}-${privateEndpoint.?service ?? 'topic'}-${index}' + serviceResourceId: topic.id + subnetResourceId: privateEndpoint.subnetResourceId + location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location + lock: privateEndpoint.?lock ?? lock + privateDnsZoneGroupName: privateEndpoint.?privateDnsZoneGroupName + privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds + roleAssignments: privateEndpoint.?roleAssignments + tags: privateEndpoint.?tags ?? tags + manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections + customDnsConfigs: privateEndpoint.?customDnsConfigs + ipConfigurations: privateEndpoint.?ipConfigurations + applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds + customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName + } +}] + +resource topic_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { + name: guid(topic.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) + properties: { + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: topic +}] + +@description('The name of the event grid topic.') +output name string = topic.name + +@description('The resource ID of the event grid topic.') +output resourceId string = topic.id + +@description('The name of the resource group the event grid topic was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = topic.location + +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(topic.identity, 'principalId') ? topic.identity.principalId : '' + +// =============== // +// Definitions // +// =============== // + +type managedIdentitiesType = { + @description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? + + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourcesIds: string[]? +}? + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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"') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type privateEndpointType = { + @description('Optional. The name of the private endpoint.') + name: string? + + @description('Optional. The location to deploy the private endpoint to.') + location: string? + + @description('Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob".') + service: string? + + @description('Required. Resource ID of the subnet where the endpoint needs to be created.') + subnetResourceId: string + + @description('Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided.') + privateDnsZoneGroupName: string? + + @description('Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones.') + privateDnsZoneResourceIds: string[]? + + @description('Optional. Custom DNS configurations.') + customDnsConfigs: { + @description('Required. Fqdn that resolves to private endpoint ip address.') + fqdn: string? + + @description('Required. A list of private ip addresses of the private endpoint.') + ipAddresses: string[] + }[]? + + @description('Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints.') + ipConfigurations: { + @description('Required. The name of the resource that is unique within a resource group.') + name: string + + @description('Required. Properties of private endpoint IP configurations.') + properties: { + @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to.') + groupId: string + + @description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to.') + memberName: string + + @description('Required. A private ip address obtained from the private endpoint\'s subnet.') + privateIPAddress: string + } + }[]? + + @description('Optional. Application security groups in which the private endpoint IP configuration is included.') + applicationSecurityGroupResourceIds: string[]? + + @description('Optional. The custom name of the network interface attached to the private endpoint.') + customNetworkInterfaceName: string? + + @description('Optional. Specify the type of lock.') + lock: lockType + + @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\'.') + roleAssignments: roleAssignmentType + + @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') + tags: object? + + @description('Optional. Manual PrivateLink Service Connections.') + manualPrivateLinkServiceConnections: array? + + @description('Optional. Enable/Disable usage telemetry for module.') + enableTelemetry: bool? +}[]? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to \'\' to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to \'AllLogs\' to collect all logs.') + categoryGroup: string? + }[]? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to \'\' to disable log collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to \'AllMetrics\' to collect all metrics.') + category: string + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @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.') + workspaceResourceId: string? + + @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.') + storageAccountResourceId: 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.') + eventHubAuthorizationRuleResourceId: 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.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? diff --git a/avm/res/event-grid/topic/main.json b/avm/res/event-grid/topic/main.json new file mode 100644 index 0000000000..1948482d82 --- /dev/null +++ b/avm/res/event-grid/topic/main.json @@ -0,0 +1,1360 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "13735548047404479215" + }, + "name": "Event Grid Topics", + "description": "This module deploys an Event Grid Topic.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourcesIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint ip address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private ip addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private ip address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "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'." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Manual PrivateLink Service Connections." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to 'AllLogs' to collect all logs." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to '' to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to 'AllMetrics' to collect all metrics." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to '' to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "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." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "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." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "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." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "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." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Event Grid Topic." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "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 and inboundIpRules are not set." + } + }, + "inboundIpRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. This can be used to restrict traffic from specific IPs instead of all IPs. Note: These are considered only if PublicNetworkAccess is enabled." + } + }, + "eventSubscriptions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Event subscriptions to deploy." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "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'." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "EventGrid Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1e241071-0855-49ea-94dc-649edcd759de')]", + "EventGrid Data Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd5a91429-5739-47e2-a06b-3470a27159e7')]", + "EventGrid EventSubscription Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '428e0ff0-5e57-4d9c-a221-2c70d0e0a443')]", + "EventGrid EventSubscription Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2414bbcf-6497-4faf-8c65-045460748405')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[take(format('46d3xbcp.res.eventgrid-topic.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "topic": { + "type": "Microsoft.EventGrid/topics", + "apiVersion": "2021-06-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": { + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('inboundIpRules'))), 'Disabled', null()))]", + "inboundIpRules": "[if(empty(parameters('inboundIpRules')), null(), parameters('inboundIpRules'))]", + "disableLocalAuth": "[parameters('disableLocalAuth')]" + } + }, + "topic_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.EventGrid/topics/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "topic" + ] + }, + "topic_diagnosticSettings": { + "copy": { + "name": "topic_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.EventGrid/topics/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "metrics": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics', 'timeGrain', null(), 'enabled', true())))]", + "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'AllLogs', 'enabled', true())))]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "topic" + ] + }, + "topic_roleAssignments": { + "copy": { + "name": "topic_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.EventGrid/topics/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.EventGrid/topics', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "topic" + ] + }, + "topics_eventSubscriptions": { + "copy": { + "name": "topics_eventSubscriptions", + "count": "[length(parameters('eventSubscriptions'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-EventGrid-Topics-EventSubscriptions-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "destination": { + "value": "[parameters('eventSubscriptions')[copyIndex()].destination]" + }, + "topicName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('eventSubscriptions')[copyIndex()].name]" + }, + "deadLetterDestination": "[if(contains(parameters('eventSubscriptions'), 'deadLetterDestination'), createObject('value', parameters('eventSubscriptions')[copyIndex()].deadLetterDestination), createObject('value', createObject()))]", + "deadLetterWithResourceIdentity": "[if(contains(parameters('eventSubscriptions'), 'deadLetterWithResourceIdentity'), createObject('value', parameters('eventSubscriptions')[copyIndex()].deadLetterWithResourceIdentity), createObject('value', createObject()))]", + "deliveryWithResourceIdentity": "[if(contains(parameters('eventSubscriptions'), 'deliveryWithResourceIdentity'), createObject('value', parameters('eventSubscriptions')[copyIndex()].deliveryWithResourceIdentity), createObject('value', createObject()))]", + "eventDeliverySchema": "[if(contains(parameters('eventSubscriptions'), 'eventDeliverySchema'), createObject('value', parameters('eventSubscriptions')[copyIndex()].eventDeliverySchema), createObject('value', 'EventGridSchema'))]", + "expirationTimeUtc": "[if(contains(parameters('eventSubscriptions'), 'expirationTimeUtc'), createObject('value', parameters('eventSubscriptions')[copyIndex()].expirationTimeUtc), createObject('value', ''))]", + "filter": "[if(contains(parameters('eventSubscriptions'), 'filter'), createObject('value', parameters('eventSubscriptions')[copyIndex()].filter), createObject('value', createObject()))]", + "labels": "[if(contains(parameters('eventSubscriptions'), 'labels'), createObject('value', parameters('eventSubscriptions')[copyIndex()].labels), createObject('value', createArray()))]", + "retryPolicy": "[if(contains(parameters('eventSubscriptions'), 'retryPolicy'), createObject('value', parameters('eventSubscriptions')[copyIndex()].retryPolicy), createObject('value', createObject()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "9051512137045314881" + }, + "name": "EventGrid Topic Event Subscriptions", + "description": "This module deploys an Event Grid Topic Event Subscription.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Event Subscription." + } + }, + "topicName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Event Grid Topic." + } + }, + "deadLetterDestination": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Dead Letter Destination. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#deadletterdestination-objects for more information)." + } + }, + "deadLetterWithResourceIdentity": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Dead Letter with Resource Identity Configuration. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#deadletterwithresourceidentity-objects for more information)." + } + }, + "deliveryWithResourceIdentity": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Delivery with Resource Identity Configuration. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#deliverywithresourceidentity-objects for more information)." + } + }, + "destination": { + "type": "object", + "metadata": { + "description": "Required. The destination for the event subscription. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#eventsubscriptiondestination-objects for more information)." + } + }, + "eventDeliverySchema": { + "type": "string", + "defaultValue": "EventGridSchema", + "allowedValues": [ + "CloudEventSchemaV1_0", + "CustomInputSchema", + "EventGridSchema", + "EventGridEvent" + ], + "metadata": { + "description": "Optional. The event delivery schema for the event subscription." + } + }, + "expirationTimeUtc": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The expiration time for the event subscription. Format is ISO-8601 (yyyy-MM-ddTHH:mm:ssZ)." + } + }, + "filter": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The filter for the event subscription. (See https://learn.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?pivots=deployment-language-bicep#eventsubscriptionfilter for more information)." + } + }, + "labels": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The list of user defined labels." + } + }, + "retryPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The retry policy for events. This can be used to configure the TTL and maximum number of delivery attempts and time to live for events." + } + } + }, + "resources": [ + { + "type": "Microsoft.EventGrid/topics/eventSubscriptions", + "apiVersion": "2022-06-15", + "name": "[format('{0}/{1}', parameters('topicName'), parameters('name'))]", + "properties": { + "deadLetterDestination": "[if(not(empty(parameters('deadLetterDestination'))), parameters('deadLetterDestination'), null())]", + "deadLetterWithResourceIdentity": "[if(not(empty(parameters('deadLetterWithResourceIdentity'))), parameters('deadLetterWithResourceIdentity'), null())]", + "deliveryWithResourceIdentity": "[if(not(empty(parameters('deliveryWithResourceIdentity'))), parameters('deliveryWithResourceIdentity'), null())]", + "destination": "[parameters('destination')]", + "eventDeliverySchema": "[parameters('eventDeliverySchema')]", + "expirationTimeUtc": "[if(not(empty(parameters('expirationTimeUtc'))), parameters('expirationTimeUtc'), '')]", + "filter": "[if(not(empty(parameters('filter'))), parameters('filter'), createObject())]", + "labels": "[if(not(empty(parameters('labels'))), parameters('labels'), createArray())]", + "retryPolicy": "[if(not(empty(parameters('retryPolicy'))), parameters('retryPolicy'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the event subscription." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the event subscription." + }, + "value": "[resourceId('Microsoft.EventGrid/topics/eventSubscriptions', parameters('topicName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the event subscription was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference(resourceId('Microsoft.EventGrid/topics', parameters('topicName')), '2022-06-15', 'full').location]" + } + } + } + }, + "dependsOn": [ + "topic" + ] + }, + "topic_privateEndpoints": { + "copy": { + "name": "topic_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-topic-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "groupIds": { + "value": [ + "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'topic')]" + ] + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.EventGrid/topics', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'topic'), copyIndex()))]" + }, + "serviceResourceId": { + "value": "[resourceId('Microsoft.EventGrid/topics', parameters('name'))]" + }, + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "manualPrivateLinkServiceConnections": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections')]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.21.1.54444", + "templateHash": "13152465847704433697" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "serviceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the resource that needs to be connected to the network." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "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'." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Manual PrivateLink Service Connections." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": [ + { + "name": "[parameters('name')]", + "properties": { + "privateLinkServiceId": "[parameters('serviceResourceId')]", + "groupIds": "[parameters('groupIds')]" + } + } + ], + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.21.1.54444", + "templateHash": "1698104586574073002" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "topic" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the event grid topic." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the event grid topic." + }, + "value": "[resourceId('Microsoft.EventGrid/topics', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the event grid topic was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('topic', '2021-06-01-preview', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('topic', '2021-06-01-preview', 'full').identity, 'principalId')), reference('topic', '2021-06-01-preview', 'full').identity.principalId, '')]" + } + } +} \ No newline at end of file diff --git a/avm/res/event-grid/topic/tests/e2e/defaults/main.test.bicep b/avm/res/event-grid/topic/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..9dd4c1fb02 --- /dev/null +++ b/avm/res/event-grid/topic/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,45 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-eventgrid.topics-${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 = 'egtmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + } +}] diff --git a/avm/res/event-grid/topic/tests/e2e/max/dependencies.bicep b/avm/res/event-grid/topic/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..448380e27d --- /dev/null +++ b/avm/res/event-grid/topic/tests/e2e/max/dependencies.bicep @@ -0,0 +1,89 @@ +@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 + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Required. The name of the Storage Queue to create.') +param storageQueueName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.eventgrid.azure.net' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-05-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + + resource queueService 'queueServices@2022-09-01' = { + name: 'default' + + resource queue 'queues@2022-09-01' = { + name: storageQueueName + } + } +} + +@description('The name of the created Storage Account Queue.') +output queueName string = storageAccount::queueService::queue.name + +@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 Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id diff --git a/avm/res/event-grid/topic/tests/e2e/max/main.test.bicep b/avm/res/event-grid/topic/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..6ed2b64a9d --- /dev/null +++ b/avm/res/event-grid/topic/tests/e2e/max/main.test.bicep @@ -0,0 +1,167 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-eventgrid.topics-${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 = 'egtmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}sa${serviceShort}' + storageQueueName: 'dep${namePrefix}sq${serviceShort}' + location: location + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + eventSubscriptions: [ { + name: '${namePrefix}${serviceShort}001' + expirationTimeUtc: '2099-01-01T11:00:21.715Z' + filter: { + isSubjectCaseSensitive: false + enableAdvancedFilteringOnArrays: true + } + retryPolicy: { + maxDeliveryAttempts: 10 + eventTimeToLive: '120' + } + eventDeliverySchema: 'CloudEventSchemaV1_0' + destination: { + endpointType: 'StorageQueue' + properties: { + resourceId: nestedDependencies.outputs.storageAccountResourceId + queueMessageTimeToLiveInSeconds: 86400 + queueName: nestedDependencies.outputs.queueName + } + } + } ] + inboundIpRules: [ + { + action: 'Allow' + ipMask: '40.74.28.0/23' + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + service: 'topic' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +}] + + diff --git a/avm/res/event-grid/topic/tests/e2e/pe/dependencies.bicep b/avm/res/event-grid/topic/tests/e2e/pe/dependencies.bicep new file mode 100644 index 0000000000..4d31fc9282 --- /dev/null +++ b/avm/res/event-grid/topic/tests/e2e/pe/dependencies.bicep @@ -0,0 +1,49 @@ +@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 + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.eventgrid.azure.net' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id diff --git a/avm/res/event-grid/topic/tests/e2e/pe/main.test.bicep b/avm/res/event-grid/topic/tests/e2e/pe/main.test.bicep new file mode 100644 index 0000000000..0f583084f8 --- /dev/null +++ b/avm/res/event-grid/topic/tests/e2e/pe/main.test.bicep @@ -0,0 +1,74 @@ +targetScope = 'subscription' + +metadata name = 'Using private endpoint' +metadata description = 'This instance deploys the module with the private endpoint.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-eventgrid.topics-${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 = 'egtpe' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + subnetResourceId: nestedDependencies.outputs.subnetResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +}] + diff --git a/avm/res/event-grid/topic/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/event-grid/topic/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 0000000000..448380e27d --- /dev/null +++ b/avm/res/event-grid/topic/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,89 @@ +@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 + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Required. The name of the Storage Queue to create.') +param storageQueueName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.eventgrid.azure.net' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-05-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + + resource queueService 'queueServices@2022-09-01' = { + name: 'default' + + resource queue 'queues@2022-09-01' = { + name: storageQueueName + } + } +} + +@description('The name of the created Storage Account Queue.') +output queueName string = storageAccount::queueService::queue.name + +@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 Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id diff --git a/avm/res/event-grid/topic/tests/e2e/waf-aligned/main.test.bicep b/avm/res/event-grid/topic/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..1d48186b98 --- /dev/null +++ b/avm/res/event-grid/topic/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,133 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-eventgrid.topics-${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 = 'egtwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}sa${serviceShort}' + storageQueueName: 'dep${namePrefix}sq${serviceShort}' + location: location + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + eventSubscriptions: [ { + name: '${namePrefix}${serviceShort}001' + expirationTimeUtc: '2099-01-01T11:00:21.715Z' + filter: { + isSubjectCaseSensitive: false + enableAdvancedFilteringOnArrays: true + } + retryPolicy: { + maxDeliveryAttempts: 10 + eventTimeToLive: '120' + } + eventDeliverySchema: 'CloudEventSchemaV1_0' + destination: { + endpointType: 'StorageQueue' + properties: { + resourceId: nestedDependencies.outputs.storageAccountResourceId + queueMessageTimeToLiveInSeconds: 86400 + queueName: nestedDependencies.outputs.queueName + } + } + } ] + inboundIpRules: [] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + service: 'topic' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +}] + + diff --git a/avm/res/event-grid/topic/version.json b/avm/res/event-grid/topic/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/res/event-grid/topic/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From 5c7ccc36ed1eb0d37e1ea73c8c2f885525b2474a Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Mon, 27 Nov 2023 10:34:47 +0100 Subject: [PATCH 05/22] feat: Enabled additional ways to specify role assignments (#663) ## Description - Updated the way roles are resolved - Regenerated docs | Pipeline | | - | | [![avm.res.key-vault.vault](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2FroleAssignmentUpdate&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) | --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/batch/batch-account/README.md | 126 +++----- avm/res/batch/batch-account/main.bicep | 8 +- avm/res/batch/batch-account/main.json | 10 +- .../tests/e2e/defaults/main.test.bicep | 12 - .../tests/e2e/max/main.test.bicep | 23 +- .../tests/e2e/waf-aligned/main.test.bicep | 6 - avm/res/cognitive-services/account/README.md | 260 ++-------------- avm/res/cognitive-services/account/main.bicep | 8 +- avm/res/cognitive-services/account/main.json | 10 +- .../tests/e2e/defaults/main.test.bicep | 14 - .../account/tests/e2e/max/main.test.bicep | 18 +- .../account/tests/e2e/speech/main.test.bicep | 10 - .../main.test.bicep | 12 - .../main.test.bicep | 12 - .../tests/e2e/waf-aligned/main.test.bicep | 8 - avm/res/compute/ssh-public-key/README.md | 72 +++-- avm/res/compute/ssh-public-key/main.bicep | 6 +- avm/res/compute/ssh-public-key/main.json | 8 +- .../tests/e2e/defaults/main.test.bicep | 5 - .../tests/e2e/max/main.test.bicep | 12 +- .../tests/e2e/waf-aligned/main.test.bicep | 12 +- .../flexible-server/README.md | 84 ++++- .../flexible-server/main.bicep | 2 +- .../flexible-server/main.json | 4 +- .../tests/e2e/encr/main.test.bicep | 5 - .../tests/e2e/private/main.test.bicep | 17 ++ .../tests/e2e/public/dependencies.bicep | 3 + .../tests/e2e/public/main.test.bicep | 17 ++ avm/res/event-grid/domain/README.md | 44 ++- avm/res/event-grid/domain/main.bicep | 8 +- avm/res/event-grid/domain/main.json | 10 +- .../domain/tests/e2e/defaults/main.test.bicep | 10 +- .../domain/tests/e2e/max/main.test.bicep | 13 +- avm/res/event-grid/system-topic/README.md | 24 +- avm/res/event-grid/system-topic/main.bicep | 2 +- avm/res/event-grid/system-topic/main.json | 4 +- .../tests/e2e/max/main.test.bicep | 12 +- avm/res/insights/action-group/README.md | 124 ++------ avm/res/insights/action-group/main.bicep | 6 +- avm/res/insights/action-group/main.json | 8 +- .../tests/e2e/defaults/main.test.bicep | 14 - .../tests/e2e/max/main.test.bicep | 12 +- .../tests/e2e/waf-aligned/main.test.bicep | 12 - avm/res/insights/component/README.md | 32 +- avm/res/insights/component/main.bicep | 6 +- avm/res/insights/component/main.json | 8 +- .../component/tests/e2e/max/main.test.bicep | 12 +- avm/res/key-vault/vault/README.md | 144 +++++---- .../key-vault/vault/access-policy/main.json | 4 +- avm/res/key-vault/vault/key/README.md | 8 +- avm/res/key-vault/vault/key/main.bicep | 6 +- avm/res/key-vault/vault/key/main.json | 10 +- avm/res/key-vault/vault/main.bicep | 8 +- avm/res/key-vault/vault/main.json | 36 +-- avm/res/key-vault/vault/secret/README.md | 8 +- avm/res/key-vault/vault/secret/main.bicep | 6 +- avm/res/key-vault/vault/secret/main.json | 10 +- .../vault/tests/e2e/defaults/main.test.bicep | 10 - .../vault/tests/e2e/max/main.test.bicep | 43 ++- .../tests/e2e/waf-aligned/main.test.bicep | 3 - .../extension/README.md | 36 --- .../tests/e2e/defaults/main.test.bicep | 6 - .../extension/tests/e2e/max/main.test.bicep | 3 - .../tests/e2e/waf-aligned/main.test.bicep | 3 - .../flux-configuration/README.md | 24 -- .../tests/e2e/defaults/main.test.bicep | 3 - .../tests/e2e/max/main.test.bicep | 3 - .../tests/e2e/waf-aligned/main.test.bicep | 3 - avm/res/logic/workflow/README.md | 44 +-- avm/res/logic/workflow/main.bicep | 6 +- avm/res/logic/workflow/main.json | 8 +- .../tests/e2e/defaults/main.test.bicep | 4 - .../workflow/tests/e2e/max/main.test.bicep | 12 +- .../network/dns-forwarding-ruleset/README.md | 64 ++-- .../network/dns-forwarding-ruleset/main.bicep | 6 +- .../network/dns-forwarding-ruleset/main.json | 8 +- .../tests/e2e/defaults/main.test.bicep | 7 - .../tests/e2e/max/main.test.bicep | 12 +- .../tests/e2e/waf-aligned/main.test.bicep | 5 - avm/res/network/dns-resolver/README.md | 56 ++-- avm/res/network/dns-resolver/main.bicep | 6 +- avm/res/network/dns-resolver/main.json | 8 +- .../tests/e2e/defaults/main.test.bicep | 7 - .../tests/e2e/max/main.test.bicep | 12 +- .../tests/e2e/waf-aligned/main.test.bicep | 2 - avm/res/network/dns-zone/README.md | 288 +++++++++++------- avm/res/network/dns-zone/a/README.md | 8 +- avm/res/network/dns-zone/a/main.bicep | 6 +- avm/res/network/dns-zone/a/main.json | 8 +- avm/res/network/dns-zone/aaaa/README.md | 8 +- avm/res/network/dns-zone/aaaa/main.bicep | 6 +- avm/res/network/dns-zone/aaaa/main.json | 8 +- avm/res/network/dns-zone/caa/README.md | 8 +- avm/res/network/dns-zone/caa/main.bicep | 6 +- avm/res/network/dns-zone/caa/main.json | 8 +- avm/res/network/dns-zone/cname/README.md | 8 +- avm/res/network/dns-zone/cname/main.bicep | 6 +- avm/res/network/dns-zone/cname/main.json | 8 +- avm/res/network/dns-zone/main.bicep | 6 +- avm/res/network/dns-zone/main.json | 88 +++--- avm/res/network/dns-zone/mx/README.md | 8 +- avm/res/network/dns-zone/mx/main.bicep | 6 +- avm/res/network/dns-zone/mx/main.json | 8 +- avm/res/network/dns-zone/ns/README.md | 8 +- avm/res/network/dns-zone/ns/main.bicep | 6 +- avm/res/network/dns-zone/ns/main.json | 8 +- avm/res/network/dns-zone/ptr/README.md | 8 +- avm/res/network/dns-zone/ptr/main.bicep | 6 +- avm/res/network/dns-zone/ptr/main.json | 8 +- avm/res/network/dns-zone/soa/README.md | 8 +- avm/res/network/dns-zone/soa/main.bicep | 6 +- avm/res/network/dns-zone/soa/main.json | 8 +- avm/res/network/dns-zone/srv/README.md | 8 +- avm/res/network/dns-zone/srv/main.bicep | 6 +- avm/res/network/dns-zone/srv/main.json | 8 +- .../tests/e2e/defaults/main.test.bicep | 14 - .../dns-zone/tests/e2e/max/main.test.bicep | 96 +++++- .../tests/e2e/waf-aligned/main.test.bicep | 9 - avm/res/network/dns-zone/txt/README.md | 8 +- avm/res/network/dns-zone/txt/main.bicep | 6 +- avm/res/network/dns-zone/txt/main.json | 8 +- .../network/express-route-circuit/README.md | 26 +- .../network/express-route-circuit/main.bicep | 3 +- .../network/express-route-circuit/main.json | 4 +- .../tests/e2e/max/main.test.bicep | 16 +- .../network/express-route-gateway/README.md | 32 +- .../network/express-route-gateway/main.bicep | 6 +- .../network/express-route-gateway/main.json | 8 +- .../tests/e2e/max/main.test.bicep | 12 +- avm/res/network/load-balancer/README.md | 80 ++++- avm/res/network/load-balancer/main.bicep | 6 +- avm/res/network/load-balancer/main.json | 8 +- .../tests/e2e/internal/main.test.bicep | 12 +- .../tests/e2e/max/main.test.bicep | 12 +- .../tests/e2e/waf-aligned/main.test.bicep | 12 +- avm/res/network/network-interface/README.md | 48 +-- avm/res/network/network-interface/main.bicep | 6 +- avm/res/network/network-interface/main.json | 8 +- .../tests/e2e/defaults/main.test.bicep | 5 - .../tests/e2e/max/main.test.bicep | 12 +- avm/res/network/private-dns-zone/README.md | 280 +++++++++++------ avm/res/network/private-dns-zone/a/README.md | 8 +- avm/res/network/private-dns-zone/a/main.bicep | 6 +- avm/res/network/private-dns-zone/a/main.json | 8 +- .../network/private-dns-zone/aaaa/README.md | 8 +- .../network/private-dns-zone/aaaa/main.bicep | 6 +- .../network/private-dns-zone/aaaa/main.json | 8 +- .../network/private-dns-zone/cname/README.md | 8 +- .../network/private-dns-zone/cname/main.bicep | 6 +- .../network/private-dns-zone/cname/main.json | 8 +- avm/res/network/private-dns-zone/main.bicep | 6 +- avm/res/network/private-dns-zone/main.json | 72 ++--- avm/res/network/private-dns-zone/mx/README.md | 8 +- .../network/private-dns-zone/mx/main.bicep | 6 +- avm/res/network/private-dns-zone/mx/main.json | 8 +- .../network/private-dns-zone/ptr/README.md | 8 +- .../network/private-dns-zone/ptr/main.bicep | 6 +- .../network/private-dns-zone/ptr/main.json | 8 +- .../network/private-dns-zone/soa/README.md | 8 +- .../network/private-dns-zone/soa/main.bicep | 6 +- .../network/private-dns-zone/soa/main.json | 8 +- .../network/private-dns-zone/srv/README.md | 8 +- .../network/private-dns-zone/srv/main.bicep | 6 +- .../network/private-dns-zone/srv/main.json | 8 +- .../tests/e2e/defaults/main.test.bicep | 13 - .../tests/e2e/max/main.test.bicep | 96 +++++- .../tests/e2e/waf-aligned/main.test.bicep | 11 - .../network/private-dns-zone/txt/README.md | 8 +- .../network/private-dns-zone/txt/main.bicep | 6 +- .../network/private-dns-zone/txt/main.json | 8 +- avm/res/network/private-endpoint/README.md | 116 +++---- avm/res/network/private-endpoint/main.bicep | 6 +- avm/res/network/private-endpoint/main.json | 8 +- .../tests/e2e/defaults/main.test.bicep | 11 - .../tests/e2e/max/main.test.bicep | 15 +- .../tests/e2e/waf-aligned/main.test.bicep | 16 +- avm/res/network/public-ip-address/README.md | 88 +++--- avm/res/network/public-ip-address/main.bicep | 6 +- avm/res/network/public-ip-address/main.json | 8 +- .../tests/e2e/defaults/main.test.bicep | 9 - .../tests/e2e/max/main.test.bicep | 12 +- .../tests/e2e/waf-aligned/main.test.bicep | 12 +- .../operational-insights/workspace/README.md | 32 +- .../operational-insights/workspace/main.bicep | 6 +- .../operational-insights/workspace/main.json | 8 +- .../workspace/tests/e2e/max/main.test.bicep | 12 +- avm/res/power-bi-dedicated/capacity/README.md | 48 +-- .../power-bi-dedicated/capacity/main.bicep | 7 +- avm/res/power-bi-dedicated/capacity/main.json | 10 +- .../tests/e2e/defaults/main.test.bicep | 5 - .../capacity/tests/e2e/max/main.test.bicep | 12 +- .../tests/e2e/waf-aligned/main.test.bicep | 3 - avm/res/resource-graph/query/README.md | 32 +- avm/res/resource-graph/query/main.bicep | 6 +- avm/res/resource-graph/query/main.json | 8 +- .../query/tests/e2e/max/main.test.bicep | 12 +- avm/res/search/search-service/README.md | 30 +- avm/res/search/search-service/main.bicep | 8 +- avm/res/search/search-service/main.json | 10 +- .../tests/e2e/max/main.test.bicep | 9 +- avm/res/sql/server/README.md | 36 ++- avm/res/sql/server/main.bicep | 8 +- avm/res/sql/server/main.json | 10 +- .../sql/server/tests/e2e/max/main.test.bicep | 12 +- 204 files changed, 2208 insertions(+), 1903 deletions(-) diff --git a/avm/res/batch/batch-account/README.md b/avm/res/batch/batch-account/README.md index 795b929108..99ce6f78cd 100644 --- a/avm/res/batch/batch-account/README.md +++ b/avm/res/batch/batch-account/README.md @@ -56,18 +56,7 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { name: 'bbamin001' storageAccountId: '' // Non-required parameters - allowedAuthenticationModes: '' - customerManagedKey: '' - diagnosticSettings: '' - keyVaultReferenceResourceId: '' location: '' - lock: '' - managedIdentities: '' - networkProfile: '' - privateEndpoints: '' - roleAssignments: '' - storageAccessIdentityResourceId: '' - tags: '' } } ``` @@ -92,41 +81,8 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { "value": "" }, // Non-required parameters - "allowedAuthenticationModes": { - "value": "" - }, - "customerManagedKey": { - "value": "" - }, - "diagnosticSettings": { - "value": "" - }, - "keyVaultReferenceResourceId": { - "value": "" - }, "location": { "value": "" - }, - "lock": { - "value": "" - }, - "managedIdentities": { - "value": "" - }, - "networkProfile": { - "value": "" - }, - "privateEndpoints": { - "value": "" - }, - "roleAssignments": { - "value": "" - }, - "storageAccessIdentityResourceId": { - "value": "" - }, - "tags": { - "value": "" } } } @@ -242,8 +198,6 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { name: 'bbamax001' storageAccountId: '' // Non-required parameters - allowedAuthenticationModes: '' - customerManagedKey: '' diagnosticSettings: [ { eventHubAuthorizationRuleResourceId: '' @@ -253,7 +207,6 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { workspaceResourceId: '' } ] - keyVaultReferenceResourceId: '' location: '' lock: { kind: 'CanNotDelete' @@ -285,7 +238,12 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] subnetResourceId: '' @@ -300,7 +258,17 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] storageAccessIdentityResourceId: '' @@ -334,12 +302,6 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { "value": "" }, // Non-required parameters - "allowedAuthenticationModes": { - "value": "" - }, - "customerManagedKey": { - "value": "" - }, "diagnosticSettings": { "value": [ { @@ -351,9 +313,6 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { } ] }, - "keyVaultReferenceResourceId": { - "value": "" - }, "location": { "value": "" }, @@ -396,7 +355,12 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "subnetResourceId": "", @@ -413,7 +377,17 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -454,8 +428,6 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { name: 'bbawaf001' storageAccountId: '' // Non-required parameters - allowedAuthenticationModes: '' - customerManagedKey: '' diagnosticSettings: [ { eventHubAuthorizationRuleResourceId: '' @@ -464,7 +436,6 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { workspaceResourceId: '' } ] - keyVaultReferenceResourceId: '' location: '' lock: { kind: 'CanNotDelete' @@ -473,7 +444,6 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { managedIdentities: { systemAssigned: true } - networkProfile: '' poolAllocationMode: 'BatchService' privateEndpoints: [ { @@ -483,7 +453,6 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { subnetResourceId: '' } ] - roleAssignments: '' storageAccessIdentityResourceId: '' storageAuthenticationMode: 'BatchAccountManagedIdentity' tags: { @@ -515,12 +484,6 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { "value": "" }, // Non-required parameters - "allowedAuthenticationModes": { - "value": "" - }, - "customerManagedKey": { - "value": "" - }, "diagnosticSettings": { "value": [ { @@ -531,9 +494,6 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { } ] }, - "keyVaultReferenceResourceId": { - "value": "" - }, "location": { "value": "" }, @@ -548,9 +508,6 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { "systemAssigned": true } }, - "networkProfile": { - "value": "" - }, "poolAllocationMode": { "value": "BatchService" }, @@ -564,9 +521,6 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { } ] }, - "roleAssignments": { - "value": "" - }, "storageAccessIdentityResourceId": { "value": "" }, @@ -618,7 +572,7 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { | [`poolAllocationMode`](#parameter-poolallocationmode) | string | The allocation mode for creating pools in the Batch account. Determines which quota will be used. | | [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | | [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | 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 networkProfile is not set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`storageAccessIdentityResourceId`](#parameter-storageaccessidentityresourceid) | string | The resource ID of a user assigned identity assigned to pools which have compute nodes that need access to auto-storage. | | [`storageAuthenticationMode`](#parameter-storageauthenticationmode) | string | The authentication mode which the Batch service will use to manage the auto-storage account. | | [`tags`](#parameter-tags) | object | Tags of the resource. | @@ -925,7 +879,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | No | string | Optional. The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | No | string | Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | No | array | Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | -| [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | array | 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'. | +| [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | array | Optional. Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | No | string | Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | | [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | Yes | string | Required. Resource ID of the subnet where the endpoint needs to be created. | | [`tags`](#parameter-privateendpointstags) | No | object | Optional. Tags to be applied on all resources/resource groups in this deployment. | @@ -1047,7 +1001,7 @@ Optional. The private DNS zone groups to associate the private endpoint with. A ### Parameter: `privateEndpoints.roleAssignments` -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'. +Optional. Array of role assignments to create. - Required: No - Type: array @@ -1090,7 +1044,7 @@ Whether or not public network access is allowed for this resource. For security ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -1103,7 +1057,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -1151,7 +1105,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/batch/batch-account/main.bicep b/avm/res/batch/batch-account/main.bicep index f2774831b2..147b04221a 100644 --- a/avm/res/batch/batch-account/main.bicep +++ b/avm/res/batch/batch-account/main.bicep @@ -48,7 +48,7 @@ param networkProfile networkProfileType @description('Optional. The lock settings of the service.') param lock lockType -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. Tags of the resource.') @@ -231,7 +231,7 @@ module batchAccount_privateEndpoints 'br/public:avm/res/network/private-endpoint resource batchAccount_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(batchAccount.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -300,7 +300,7 @@ type diagnosticSettingType = { }[]? type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') @@ -364,7 +364,7 @@ type privateEndpointType = { @description('Optional. Specify the type of lock.') lock: lockType - @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\'.') + @description('Optional. Array of role assignments to create.') roleAssignments: roleAssignmentType? @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') diff --git a/avm/res/batch/batch-account/main.json b/avm/res/batch/batch-account/main.json index 9441472131..8ba5f23677 100644 --- a/avm/res/batch/batch-account/main.json +++ b/avm/res/batch/batch-account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "11850231744835953417" + "templateHash": "16960327826957585535" }, "name": "Batch Accounts", "description": "This module deploys a Batch Account.", @@ -127,7 +127,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -307,7 +307,7 @@ "$ref": "#/definitions/roleAssignmentType", "nullable": true, "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -542,7 +542,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -742,7 +742,7 @@ "scope": "[format('Microsoft.Batch/batchAccounts/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Batch/batchAccounts', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/batch/batch-account/tests/e2e/defaults/main.test.bicep b/avm/res/batch/batch-account/tests/e2e/defaults/main.test.bicep index b0bb748e7c..53caff787a 100644 --- a/avm/res/batch/batch-account/tests/e2e/defaults/main.test.bicep +++ b/avm/res/batch/batch-account/tests/e2e/defaults/main.test.bicep @@ -52,17 +52,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: '${namePrefix}${serviceShort}001' location: location storageAccountId: nestedDependencies.outputs.storageAccountResourceId - // Workaround for PSRule - storageAccessIdentityResourceId: null - keyVaultReferenceResourceId: null - networkProfile: null - tags: null - allowedAuthenticationModes: null - diagnosticSettings: null - roleAssignments: null - privateEndpoints: null - managedIdentities: null - customerManagedKey: null - lock: null } }] diff --git a/avm/res/batch/batch-account/tests/e2e/max/main.test.bicep b/avm/res/batch/batch-account/tests/e2e/max/main.test.bicep index 9fb6a700fb..4ec2feaf2e 100644 --- a/avm/res/batch/batch-account/tests/e2e/max/main.test.bicep +++ b/avm/res/batch/batch-account/tests/e2e/max/main.test.bicep @@ -95,7 +95,12 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' } roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -117,7 +122,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' } roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -132,9 +147,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Environment: 'Non-Prod' Role: 'DeploymentValidation' } - // Workaround for PSRule - keyVaultReferenceResourceId: null - allowedAuthenticationModes: null - customerManagedKey: null } }] diff --git a/avm/res/batch/batch-account/tests/e2e/waf-aligned/main.test.bicep b/avm/res/batch/batch-account/tests/e2e/waf-aligned/main.test.bicep index 80511fa7ea..701d8bd5e1 100644 --- a/avm/res/batch/batch-account/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/batch/batch-account/tests/e2e/waf-aligned/main.test.bicep @@ -99,11 +99,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Environment: 'Non-Prod' Role: 'DeploymentValidation' } - // Workaround for PSRule - keyVaultReferenceResourceId: null - networkProfile: null - allowedAuthenticationModes: null - roleAssignments: null - customerManagedKey: null } }] diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index df30caeb6c..5991ef3fba 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -58,20 +58,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = { kind: 'SpeechServices' name: 'csamin001' // Non-required parameters - allowedFqdnList: '' - apiProperties: '' - customerManagedKey: '' - customSubDomainName: '' - diagnosticSettings: '' location: '' - lock: '' - managedIdentities: '' - migrationToken: '' - networkAcls: '' - privateEndpoints: '' - roleAssignments: '' - tags: '' - userOwnedStorage: '' } } ``` @@ -96,47 +83,8 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "value": "csamin001" }, // Non-required parameters - "allowedFqdnList": { - "value": "" - }, - "apiProperties": { - "value": "" - }, - "customerManagedKey": { - "value": "" - }, - "customSubDomainName": { - "value": "" - }, - "diagnosticSettings": { - "value": "" - }, "location": { "value": "" - }, - "lock": { - "value": "" - }, - "managedIdentities": { - "value": "" - }, - "migrationToken": { - "value": "" - }, - "networkAcls": { - "value": "" - }, - "privateEndpoints": { - "value": "" - }, - "roleAssignments": { - "value": "" - }, - "tags": { - "value": "" - }, - "userOwnedStorage": { - "value": "" } } } @@ -162,9 +110,6 @@ module account 'br/public:avm/res/cognitive-services/account:' = { kind: 'Face' name: 'csamax001' // Non-required parameters - allowedFqdnList: '' - apiProperties: '' - customerManagedKey: '' customSubDomainName: 'xcsamax' diagnosticSettings: [ { @@ -205,7 +150,6 @@ module account 'br/public:avm/res/cognitive-services/account:' = { '' ] } - migrationToken: '' networkAcls: { defaultAction: 'Deny' ipRules: [ @@ -238,7 +182,17 @@ module account 'br/public:avm/res/cognitive-services/account:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] sku: 'S0' @@ -247,7 +201,6 @@ module account 'br/public:avm/res/cognitive-services/account:' = { 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userOwnedStorage: '' } } ``` @@ -272,15 +225,6 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "value": "csamax001" }, // Non-required parameters - "allowedFqdnList": { - "value": "" - }, - "apiProperties": { - "value": "" - }, - "customerManagedKey": { - "value": "" - }, "customSubDomainName": { "value": "xcsamax" }, @@ -331,9 +275,6 @@ module account 'br/public:avm/res/cognitive-services/account:' = { ] } }, - "migrationToken": { - "value": "" - }, "networkAcls": { "value": { "defaultAction": "Deny", @@ -373,7 +314,17 @@ module account 'br/public:avm/res/cognitive-services/account:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -386,9 +337,6 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userOwnedStorage": { - "value": "" } } } @@ -414,21 +362,14 @@ module account 'br/public:avm/res/cognitive-services/account:' = { kind: 'SpeechServices' name: 'csaspeech001' // Non-required parameters - allowedFqdnList: '' - apiProperties: '' - customerManagedKey: '' customSubDomainName: 'speechdomain' - diagnosticSettings: '' location: '' - lock: '' managedIdentities: { systemAssigned: true userAssignedResourceIds: [ '' ] } - migrationToken: '' - networkAcls: '' privateEndpoints: [ { privateDnsZoneResourceIds: [ @@ -442,14 +383,12 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } } ] - roleAssignments: '' sku: 'S0' tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userOwnedStorage: '' } } ``` @@ -474,27 +413,12 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "value": "csaspeech001" }, // Non-required parameters - "allowedFqdnList": { - "value": "" - }, - "apiProperties": { - "value": "" - }, - "customerManagedKey": { - "value": "" - }, "customSubDomainName": { "value": "speechdomain" }, - "diagnosticSettings": { - "value": "" - }, "location": { "value": "" }, - "lock": { - "value": "" - }, "managedIdentities": { "value": { "systemAssigned": true, @@ -503,12 +427,6 @@ module account 'br/public:avm/res/cognitive-services/account:' = { ] } }, - "migrationToken": { - "value": "" - }, - "networkAcls": { - "value": "" - }, "privateEndpoints": { "value": [ { @@ -524,9 +442,6 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } ] }, - "roleAssignments": { - "value": "" - }, "sku": { "value": "S0" }, @@ -536,9 +451,6 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userOwnedStorage": { - "value": "" } } } @@ -564,28 +476,17 @@ module account 'br/public:avm/res/cognitive-services/account:' = { kind: 'SpeechServices' name: '' // Non-required parameters - allowedFqdnList: '' - apiProperties: '' customerManagedKey: { keyName: '' keyVaultResourceId: '' } - customSubDomainName: '' - diagnosticSettings: '' location: '' - lock: '' managedIdentities: { systemAssigned: true } - migrationToken: '' - networkAcls: '' - privateEndpoints: '' publicNetworkAccess: 'Enabled' restrictOutboundNetworkAccess: false - roleAssignments: '' sku: 'S0' - tags: '' - userOwnedStorage: '' } } ``` @@ -610,61 +511,28 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "value": "" }, // Non-required parameters - "allowedFqdnList": { - "value": "" - }, - "apiProperties": { - "value": "" - }, "customerManagedKey": { "value": { "keyName": "", "keyVaultResourceId": "" } }, - "customSubDomainName": { - "value": "" - }, - "diagnosticSettings": { - "value": "" - }, "location": { "value": "" }, - "lock": { - "value": "" - }, "managedIdentities": { "value": { "systemAssigned": true } }, - "migrationToken": { - "value": "" - }, - "networkAcls": { - "value": "" - }, - "privateEndpoints": { - "value": "" - }, "publicNetworkAccess": { "value": "Enabled" }, "restrictOutboundNetworkAccess": { "value": false }, - "roleAssignments": { - "value": "" - }, "sku": { "value": "S0" - }, - "tags": { - "value": "" - }, - "userOwnedStorage": { - "value": "" } } } @@ -690,31 +558,20 @@ module account 'br/public:avm/res/cognitive-services/account:' = { kind: 'SpeechServices' name: 'csaencr001' // Non-required parameters - allowedFqdnList: '' - apiProperties: '' customerManagedKey: { keyName: '' keyVaultResourceId: '' userAssignedIdentityResourceId: '' } - customSubDomainName: '' - diagnosticSettings: '' location: '' - lock: '' managedIdentities: { userAssignedResourceIds: [ '' ] } - migrationToken: '' - networkAcls: '' - privateEndpoints: '' publicNetworkAccess: 'Enabled' restrictOutboundNetworkAccess: false - roleAssignments: '' sku: 'S0' - tags: '' - userOwnedStorage: '' } } ``` @@ -739,12 +596,6 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "value": "csaencr001" }, // Non-required parameters - "allowedFqdnList": { - "value": "" - }, - "apiProperties": { - "value": "" - }, "customerManagedKey": { "value": { "keyName": "", @@ -752,18 +603,9 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "userAssignedIdentityResourceId": "" } }, - "customSubDomainName": { - "value": "" - }, - "diagnosticSettings": { - "value": "" - }, "location": { "value": "" }, - "lock": { - "value": "" - }, "managedIdentities": { "value": { "userAssignedResourceIds": [ @@ -771,32 +613,14 @@ module account 'br/public:avm/res/cognitive-services/account:' = { ] } }, - "migrationToken": { - "value": "" - }, - "networkAcls": { - "value": "" - }, - "privateEndpoints": { - "value": "" - }, "publicNetworkAccess": { "value": "Enabled" }, "restrictOutboundNetworkAccess": { "value": false }, - "roleAssignments": { - "value": "" - }, "sku": { "value": "S0" - }, - "tags": { - "value": "" - }, - "userOwnedStorage": { - "value": "" } } } @@ -822,9 +646,6 @@ module account 'br/public:avm/res/cognitive-services/account:' = { kind: 'Face' name: 'csawaf001' // Non-required parameters - allowedFqdnList: '' - apiProperties: '' - customerManagedKey: '' customSubDomainName: 'xcsawaf' diagnosticSettings: [ { @@ -842,8 +663,6 @@ module account 'br/public:avm/res/cognitive-services/account:' = { managedIdentities: { systemAssigned: true } - migrationToken: '' - networkAcls: '' privateEndpoints: [ { privateDnsZoneResourceIds: [ @@ -857,14 +676,12 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } } ] - roleAssignments: '' sku: 'S0' tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userOwnedStorage: '' } } ``` @@ -889,15 +706,6 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "value": "csawaf001" }, // Non-required parameters - "allowedFqdnList": { - "value": "" - }, - "apiProperties": { - "value": "" - }, - "customerManagedKey": { - "value": "" - }, "customSubDomainName": { "value": "xcsawaf" }, @@ -925,12 +733,6 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "systemAssigned": true } }, - "migrationToken": { - "value": "" - }, - "networkAcls": { - "value": "" - }, "privateEndpoints": { "value": [ { @@ -946,9 +748,6 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } ] }, - "roleAssignments": { - "value": "" - }, "sku": { "value": "S0" }, @@ -958,9 +757,6 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userOwnedStorage": { - "value": "" } } } @@ -1005,7 +801,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = { | [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | 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. | | [`restore`](#parameter-restore) | bool | Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists. | | [`restrictOutboundNetworkAccess`](#parameter-restrictoutboundnetworkaccess) | bool | Restrict outbound network access. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`sku`](#parameter-sku) | string | SKU of the Cognitive Services resource. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`userOwnedStorage`](#parameter-userownedstorage) | array | The storage accounts for this resource. | @@ -1337,7 +1133,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | No | string | Optional. The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | No | string | Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | No | array | Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | -| [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | array | 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'. | +| [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | array | Optional. Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | No | string | Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | | [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | Yes | string | Required. Resource ID of the subnet where the endpoint needs to be created. | | [`tags`](#parameter-privateendpointstags) | No | object | Optional. Tags to be applied on all resources/resource groups in this deployment. | @@ -1459,7 +1255,7 @@ Optional. The private DNS zone groups to associate the private endpoint with. A ### Parameter: `privateEndpoints.roleAssignments` -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'. +Optional. Array of role assignments to create. - Required: No - Type: array @@ -1516,7 +1312,7 @@ Restrict outbound network access. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -1529,7 +1325,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -1577,7 +1373,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index 2450bcb0dd..62ac4428ef 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -80,7 +80,7 @@ param privateEndpoints privateEndpointType @description('Optional. The lock settings of the service.') param lock lockType -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. Tags of the resource.') @@ -288,7 +288,7 @@ module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endp resource cognitiveService_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(cognitiveService.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -360,7 +360,7 @@ type diagnosticSettingType = { }[]? type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') @@ -424,7 +424,7 @@ type privateEndpointType = { @description('Optional. Specify the type of lock.') lock: lockType - @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\'.') + @description('Optional. Array of role assignments to create.') roleAssignments: roleAssignmentType? @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index f65f92f482..5966902ed5 100644 --- a/avm/res/cognitive-services/account/main.json +++ b/avm/res/cognitive-services/account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "6109702100666638123" + "templateHash": "7267850394264518578" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -127,7 +127,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -307,7 +307,7 @@ "$ref": "#/definitions/roleAssignmentType", "nullable": true, "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -533,7 +533,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -782,7 +782,7 @@ "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/cognitive-services/account/tests/e2e/defaults/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/defaults/main.test.bicep index 2bb7f8ca38..c619a55051 100644 --- a/avm/res/cognitive-services/account/tests/e2e/defaults/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/defaults/main.test.bicep @@ -43,19 +43,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: '${namePrefix}${serviceShort}001' kind: 'SpeechServices' location: location - // Workaround for PSRule - lock: null - roleAssignments: null - diagnosticSettings: null - managedIdentities: null - privateEndpoints: null - customerManagedKey: null - customSubDomainName: null - tags: null - allowedFqdnList: null - apiProperties: null - migrationToken: null - userOwnedStorage: null - networkAcls: null } }] diff --git a/avm/res/cognitive-services/account/tests/e2e/max/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/max/main.test.bicep index 1c3ed4ad71..5ee0cd261b 100644 --- a/avm/res/cognitive-services/account/tests/e2e/max/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/max/main.test.bicep @@ -116,7 +116,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' publicNetworkAccess: 'Disabled' roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -146,11 +156,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Environment: 'Non-Prod' Role: 'DeploymentValidation' } - // Workaround for PSRule - customerManagedKey: null - allowedFqdnList: null - apiProperties: null - migrationToken: null - userOwnedStorage: null } }] diff --git a/avm/res/cognitive-services/account/tests/e2e/speech/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/speech/main.test.bicep index d30a1ce519..81dfeffc2b 100644 --- a/avm/res/cognitive-services/account/tests/e2e/speech/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/speech/main.test.bicep @@ -78,15 +78,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Environment: 'Non-Prod' Role: 'DeploymentValidation' } - // Workaround for PSRule - lock: null - roleAssignments: null - diagnosticSettings: null - customerManagedKey: null - allowedFqdnList: null - apiProperties: null - migrationToken: null - userOwnedStorage: null - networkAcls: null } }] diff --git a/avm/res/cognitive-services/account/tests/e2e/system-assigned-cmk-encryption/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/system-assigned-cmk-encryption/main.test.bicep index a647550cb1..66e388d874 100644 --- a/avm/res/cognitive-services/account/tests/e2e/system-assigned-cmk-encryption/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/system-assigned-cmk-encryption/main.test.bicep @@ -67,17 +67,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' systemAssigned: true } restrictOutboundNetworkAccess: false - // Workaround for PSRule - lock: null - roleAssignments: null - diagnosticSettings: null - privateEndpoints: null - customSubDomainName: null - tags: null - allowedFqdnList: null - apiProperties: null - migrationToken: null - userOwnedStorage: null - networkAcls: null } }] diff --git a/avm/res/cognitive-services/account/tests/e2e/user-assigned-cmk-encryption/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/user-assigned-cmk-encryption/main.test.bicep index cd1c861add..945d40593a 100644 --- a/avm/res/cognitive-services/account/tests/e2e/user-assigned-cmk-encryption/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/user-assigned-cmk-encryption/main.test.bicep @@ -70,17 +70,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] } restrictOutboundNetworkAccess: false - // Workaround for PSRule - lock: null - roleAssignments: null - diagnosticSettings: null - privateEndpoints: null - customSubDomainName: null - tags: null - allowedFqdnList: null - apiProperties: null - migrationToken: null - userOwnedStorage: null - networkAcls: null } }] diff --git a/avm/res/cognitive-services/account/tests/e2e/waf-aligned/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/waf-aligned/main.test.bicep index 5b0fcb92c2..35fdbab8ea 100644 --- a/avm/res/cognitive-services/account/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/waf-aligned/main.test.bicep @@ -101,13 +101,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' managedIdentities: { systemAssigned: true } - // Workaround for PSRule - roleAssignments: null - customerManagedKey: null - allowedFqdnList: null - apiProperties: null - migrationToken: null - userOwnedStorage: null - networkAcls: null } }] diff --git a/avm/res/compute/ssh-public-key/README.md b/avm/res/compute/ssh-public-key/README.md index 2cf39d496e..694a53c192 100644 --- a/avm/res/compute/ssh-public-key/README.md +++ b/avm/res/compute/ssh-public-key/README.md @@ -51,10 +51,6 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = { name: 'cspkmin001' // Non-required parameters location: '' - lock: '' - publicKey: '' - roleAssignments: '' - tags: '' } } ``` @@ -78,18 +74,6 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = { // Non-required parameters "location": { "value": "" - }, - "lock": { - "value": "" - }, - "publicKey": { - "value": "" - }, - "roleAssignments": { - "value": "" - }, - "tags": { - "value": "" } } } @@ -125,7 +109,17 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] tags: { @@ -174,7 +168,17 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -219,7 +223,17 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] tags: { @@ -268,7 +282,17 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -303,7 +327,7 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = { | [`location`](#parameter-location) | string | Resource location. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | | [`publicKey`](#parameter-publickey) | string | SSH public key used to authenticate to a virtual machine through SSH. If this property is not initially provided when the resource is created, the publicKey property will be populated when generateKeyPair is called. If the public key is provided upon resource creation, the provided public key needs to be at least 2048-bit and in ssh-rsa format. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`tags`](#parameter-tags) | object | Tags of the availability set resource. | ### Parameter: `enableTelemetry` @@ -361,7 +385,7 @@ SSH public key used to authenticate to a virtual machine through SSH. If this pr ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -374,7 +398,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -422,7 +446,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/compute/ssh-public-key/main.bicep b/avm/res/compute/ssh-public-key/main.bicep index 2dbbe9c441..9ba631a117 100644 --- a/avm/res/compute/ssh-public-key/main.bicep +++ b/avm/res/compute/ssh-public-key/main.bicep @@ -19,7 +19,7 @@ param tags object? @description('Optional. The lock settings of the service.') param lock lockType -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. Enable/Disable usage telemetry for module.') @@ -73,7 +73,7 @@ resource sshPublicKeyLock 'Microsoft.Authorization/locks@2020-05-01' = if (!empt resource sshPublicKeyRoleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(sshPublicKey.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -101,7 +101,7 @@ output location string = sshPublicKey.location // ================ // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/compute/ssh-public-key/main.json b/avm/res/compute/ssh-public-key/main.json index dfaccf3b4b..0a708cec08 100644 --- a/avm/res/compute/ssh-public-key/main.json +++ b/avm/res/compute/ssh-public-key/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "14304853627075339483" + "templateHash": "17576839719630470934" }, "name": "Public SSH Keys", "description": "This module deploys a Public SSH Key.\n\n> Note: The resource does not auto-generate the key for you.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -142,7 +142,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "enableTelemetry": { @@ -217,7 +217,7 @@ "scope": "[format('Microsoft.Compute/sshPublicKeys/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Compute/sshPublicKeys', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/compute/ssh-public-key/tests/e2e/defaults/main.test.bicep b/avm/res/compute/ssh-public-key/tests/e2e/defaults/main.test.bicep index 5e5357cbee..a0aa5bb9c3 100644 --- a/avm/res/compute/ssh-public-key/tests/e2e/defaults/main.test.bicep +++ b/avm/res/compute/ssh-public-key/tests/e2e/defaults/main.test.bicep @@ -42,10 +42,5 @@ module testDeployment '../../../main.bicep' = { params: { name: '${namePrefix}-${serviceShort}001' location: location - // Workaround for PSRule - lock: null - tags: null - publicKey: null - roleAssignments: null } } diff --git a/avm/res/compute/ssh-public-key/tests/e2e/max/main.test.bicep b/avm/res/compute/ssh-public-key/tests/e2e/max/main.test.bicep index f25024da1b..f53a3e2e68 100644 --- a/avm/res/compute/ssh-public-key/tests/e2e/max/main.test.bicep +++ b/avm/res/compute/ssh-public-key/tests/e2e/max/main.test.bicep @@ -58,7 +58,17 @@ module testDeployment '../../../main.bicep' = { } roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/compute/ssh-public-key/tests/e2e/waf-aligned/main.test.bicep b/avm/res/compute/ssh-public-key/tests/e2e/waf-aligned/main.test.bicep index 1fb3520227..74feeb11d7 100644 --- a/avm/res/compute/ssh-public-key/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/compute/ssh-public-key/tests/e2e/waf-aligned/main.test.bicep @@ -59,7 +59,17 @@ module testDeployment '../../../main.bicep' = { } roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/db-for-postgre-sql/flexible-server/README.md b/avm/res/db-for-postgre-sql/flexible-server/README.md index 7581109ac8..90f1e6c85f 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/README.md +++ b/avm/res/db-for-postgre-sql/flexible-server/README.md @@ -126,11 +126,6 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:' userAssignedIdentityResourceId: '' } - databases: [ - { - name: 'testdb1' - } - ] location: '' managedIdentities: { userAssignedResourceIds: [ @@ -177,13 +172,6 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:" } }, - "databases": { - "value": [ - { - "name": "testdb1" - } - ] - }, "location": { "value": "" }, @@ -261,6 +249,23 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:' privateDnsZoneArmResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -353,6 +358,25 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:" }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, "tags": { "value": { "Environment": "Non-Prod", @@ -444,6 +468,23 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] storageSizeGB: 1024 tags: { Environment: 'Non-Prod' @@ -555,6 +596,25 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:" }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, "storageSizeGB": { "value": 1024 }, diff --git a/avm/res/db-for-postgre-sql/flexible-server/main.bicep b/avm/res/db-for-postgre-sql/flexible-server/main.bicep index e8848230b2..53323a5cbf 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/main.bicep +++ b/avm/res/db-for-postgre-sql/flexible-server/main.bicep @@ -265,7 +265,7 @@ resource flexibleServer_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!e resource flexibleServer_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(flexibleServer.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType diff --git a/avm/res/db-for-postgre-sql/flexible-server/main.json b/avm/res/db-for-postgre-sql/flexible-server/main.json index 321172e06d..eafc460195 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/main.json +++ b/avm/res/db-for-postgre-sql/flexible-server/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "16677412780876531239" + "templateHash": "16619948614416914146" }, "name": "DBforPostgreSQL Flexible Servers", "description": "This module deploys a DBforPostgreSQL Flexible Server.", @@ -660,7 +660,7 @@ "scope": "[format('Microsoft.DBforPostgreSQL/flexibleServers/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.DBforPostgreSQL/flexibleServers', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/encr/main.test.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/encr/main.test.bicep index ac13e0f6e2..31d41df16b 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/encr/main.test.bicep +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/encr/main.test.bicep @@ -64,11 +64,6 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' administratorLoginPassword: password skuName: 'Standard_D2s_v3' tier: 'GeneralPurpose' - databases: [ - { - name: 'testdb1' - } - ] customerManagedKey: { keyName: nestedDependencies.outputs.keyName keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/private/main.test.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/private/main.test.bicep index 727a1e8709..455f22b552 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/private/main.test.bicep +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/private/main.test.bicep @@ -97,6 +97,23 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' } ] delegatedSubnetResourceId: nestedDependencies.outputs.subnetResourceId + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] diagnosticSettings: [ { name: 'customSetting' diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/dependencies.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/dependencies.bicep index e8cc3c805a..b17a554871 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/dependencies.bicep +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/dependencies.bicep @@ -15,5 +15,8 @@ output managedIdentityResourceId string = managedIdentity.id @description('The client ID of the created Managed Identity.') output managedIdentityClientId string = managedIdentity.properties.clientId +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + @description('The name of the created Managed Identity.') output managedIdentityName string = managedIdentity.name diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/main.test.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/main.test.bicep index 910da4a643..01878744ec 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/main.test.bicep +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/main.test.bicep @@ -91,6 +91,23 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: 'testdb2' } ] + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] diagnosticSettings: [ { name: 'customSetting' diff --git a/avm/res/event-grid/domain/README.md b/avm/res/event-grid/domain/README.md index 5aa2ced49b..1f379ec282 100644 --- a/avm/res/event-grid/domain/README.md +++ b/avm/res/event-grid/domain/README.md @@ -52,8 +52,6 @@ module domain 'br/public:avm/res/event-grid/domain:' = { name: 'egdmin001' // Non-required parameters location: '' - managedIdentities: '' - privateEndpoints: '' } } ``` @@ -77,12 +75,6 @@ module domain 'br/public:avm/res/event-grid/domain:' = { // Non-required parameters "location": { "value": "" - }, - "managedIdentities": { - "value": "" - }, - "privateEndpoints": { - "value": "" } } } @@ -150,7 +142,17 @@ module domain 'br/public:avm/res/event-grid/domain:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] tags: { @@ -236,7 +238,17 @@ module domain 'br/public:avm/res/event-grid/domain:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -513,7 +525,7 @@ module domain 'br/public:avm/res/event-grid/domain:' = { | [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | | [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | | [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | 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 inboundIpRules are not set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`topics`](#parameter-topics) | array | The topic names which are associated with the domain. | @@ -753,7 +765,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | No | string | Optional. The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | No | string | Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | No | array | Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | -| [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | array | 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'. | +| [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | array | Optional. Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | No | string | Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | | [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | Yes | string | Required. Resource ID of the subnet where the endpoint needs to be created. | | [`tags`](#parameter-privateendpointstags) | No | object | Optional. Tags to be applied on all resources/resource groups in this deployment. | @@ -905,7 +917,7 @@ Optional. The private DNS zone groups to associate the private endpoint with. A ### Parameter: `privateEndpoints.roleAssignments` -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'. +Optional. Array of role assignments to create. - Required: No - Type: array @@ -948,7 +960,7 @@ Whether or not public network access is allowed for this resource. For security ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -961,7 +973,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -1009,7 +1021,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/event-grid/domain/main.bicep b/avm/res/event-grid/domain/main.bicep index d393f421b4..8e0989bc16 100644 --- a/avm/res/event-grid/domain/main.bicep +++ b/avm/res/event-grid/domain/main.bicep @@ -31,7 +31,7 @@ param diagnosticSettings diagnosticSettingType @description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') param privateEndpoints privateEndpointType -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. The lock settings of the service.') @@ -172,7 +172,7 @@ module domain_privateEndpoints 'br/public:avm-res-network-privateendpoint:0.1.1' resource domain_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(domain.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -219,7 +219,7 @@ type lockType = { }? type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') @@ -296,7 +296,7 @@ type privateEndpointType = { @description('Optional. Specify the type of lock.') lock: lockType - @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\'.') + @description('Optional. Array of role assignments to create.') roleAssignments: roleAssignmentType @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') diff --git a/avm/res/event-grid/domain/main.json b/avm/res/event-grid/domain/main.json index 104438461b..11dad76f0e 100644 --- a/avm/res/event-grid/domain/main.json +++ b/avm/res/event-grid/domain/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "4425094317153715056" + "templateHash": "801183698261065090" }, "name": "Event Grid Domains", "description": "This module deploys an Event Grid Domain.", @@ -69,7 +69,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -274,7 +274,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -471,7 +471,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "lock": { @@ -613,7 +613,7 @@ "scope": "[format('Microsoft.EventGrid/domains/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.EventGrid/domains', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/event-grid/domain/tests/e2e/defaults/main.test.bicep b/avm/res/event-grid/domain/tests/e2e/defaults/main.test.bicep index 8fa9a31c96..764a08ee2f 100644 --- a/avm/res/event-grid/domain/tests/e2e/defaults/main.test.bicep +++ b/avm/res/event-grid/domain/tests/e2e/defaults/main.test.bicep @@ -41,14 +41,6 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' params: { name: '${namePrefix}${serviceShort}001' - location: location - - // Workaround for PSRule - managedIdentities: null - privateEndpoints: null + location: location } }] - - - - diff --git a/avm/res/event-grid/domain/tests/e2e/max/main.test.bicep b/avm/res/event-grid/domain/tests/e2e/max/main.test.bicep index 95b5b61407..c115211d69 100644 --- a/avm/res/event-grid/domain/tests/e2e/max/main.test.bicep +++ b/avm/res/event-grid/domain/tests/e2e/max/main.test.bicep @@ -106,7 +106,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -121,4 +131,3 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] } }] - diff --git a/avm/res/event-grid/system-topic/README.md b/avm/res/event-grid/system-topic/README.md index d3694897e7..ff0a907c0f 100644 --- a/avm/res/event-grid/system-topic/README.md +++ b/avm/res/event-grid/system-topic/README.md @@ -155,7 +155,17 @@ module systemTopic 'br/public:avm/res/event-grid/system-topic:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] tags: { @@ -250,7 +260,17 @@ module systemTopic 'br/public:avm/res/event-grid/system-topic:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, diff --git a/avm/res/event-grid/system-topic/main.bicep b/avm/res/event-grid/system-topic/main.bicep index 7c534a36d5..5a69d444ce 100644 --- a/avm/res/event-grid/system-topic/main.bicep +++ b/avm/res/event-grid/system-topic/main.bicep @@ -140,7 +140,7 @@ resource systemTopic_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2 resource systemTopic_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(systemTopic.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType diff --git a/avm/res/event-grid/system-topic/main.json b/avm/res/event-grid/system-topic/main.json index a750869494..f6584347a4 100644 --- a/avm/res/event-grid/system-topic/main.json +++ b/avm/res/event-grid/system-topic/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "733235906421463654" + "templateHash": "13024100603539103519" }, "name": "Event Grid System Topics", "description": "This module deploys an Event Grid System Topic.", @@ -401,7 +401,7 @@ "scope": "[format('Microsoft.EventGrid/systemTopics/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.EventGrid/systemTopics', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/event-grid/system-topic/tests/e2e/max/main.test.bicep b/avm/res/event-grid/system-topic/tests/e2e/max/main.test.bicep index ca9d1d76c5..dab3a5cc29 100644 --- a/avm/res/event-grid/system-topic/tests/e2e/max/main.test.bicep +++ b/avm/res/event-grid/system-topic/tests/e2e/max/main.test.bicep @@ -112,7 +112,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' } roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/insights/action-group/README.md b/avm/res/insights/action-group/README.md index 3043e932ce..c7db781488 100644 --- a/avm/res/insights/action-group/README.md +++ b/avm/res/insights/action-group/README.md @@ -46,19 +46,7 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = { groupShortName: 'agiagmin001' name: 'iagmin001' // Non-required parameters - armRoleReceivers: '' - automationRunbookReceivers: '' - azureAppPushReceivers: '' - azureFunctionReceivers: '' - emailReceivers: '' - itsmReceivers: '' location: 'global' - logicAppReceivers: '' - roleAssignments: '' - smsReceivers: '' - tags: '' - voiceReceivers: '' - webhookReceivers: '' } } ``` @@ -83,44 +71,8 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = { "value": "iagmin001" }, // Non-required parameters - "armRoleReceivers": { - "value": "" - }, - "automationRunbookReceivers": { - "value": "" - }, - "azureAppPushReceivers": { - "value": "" - }, - "azureFunctionReceivers": { - "value": "" - }, - "emailReceivers": { - "value": "" - }, - "itsmReceivers": { - "value": "" - }, "location": { "value": "global" - }, - "logicAppReceivers": { - "value": "" - }, - "roleAssignments": { - "value": "" - }, - "smsReceivers": { - "value": "" - }, - "tags": { - "value": "" - }, - "voiceReceivers": { - "value": "" - }, - "webhookReceivers": { - "value": "" } } } @@ -163,7 +115,17 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] smsReceivers: [ @@ -224,7 +186,17 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -268,23 +240,12 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = { groupShortName: 'agiagwaf001' name: 'iagwaf001' // Non-required parameters - armRoleReceivers: '' - automationRunbookReceivers: '' - azureAppPushReceivers: '' - azureFunctionReceivers: '' - emailReceivers: '' - itsmReceivers: '' location: 'global' - logicAppReceivers: '' - roleAssignments: '' - smsReceivers: '' tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - voiceReceivers: '' - webhookReceivers: '' } } ``` @@ -309,48 +270,15 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = { "value": "iagwaf001" }, // Non-required parameters - "armRoleReceivers": { - "value": "" - }, - "automationRunbookReceivers": { - "value": "" - }, - "azureAppPushReceivers": { - "value": "" - }, - "azureFunctionReceivers": { - "value": "" - }, - "emailReceivers": { - "value": "" - }, - "itsmReceivers": { - "value": "" - }, "location": { "value": "global" }, - "logicAppReceivers": { - "value": "" - }, - "roleAssignments": { - "value": "" - }, - "smsReceivers": { - "value": "" - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "voiceReceivers": { - "value": "" - }, - "webhookReceivers": { - "value": "" } } } @@ -383,7 +311,7 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = { | [`itsmReceivers`](#parameter-itsmreceivers) | array | The list of ITSM receivers that are part of this action group. | | [`location`](#parameter-location) | string | Location for all resources. | | [`logicAppReceivers`](#parameter-logicappreceivers) | array | The list of logic app receivers that are part of this action group. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`smsReceivers`](#parameter-smsreceivers) | array | The list of SMS receivers that are part of this action group. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`voiceReceivers`](#parameter-voicereceivers) | array | The list of voice receivers that are part of this action group. | @@ -466,7 +394,7 @@ The name of the action group. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -479,7 +407,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -527,7 +455,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/insights/action-group/main.bicep b/avm/res/insights/action-group/main.bicep index 61e9dff831..70e6e415c4 100644 --- a/avm/res/insights/action-group/main.bicep +++ b/avm/res/insights/action-group/main.bicep @@ -11,7 +11,7 @@ param groupShortName string @description('Optional. Indicates whether this action group is enabled. If an action group is not enabled, then none of its receivers will receive communications.') param enabled bool = true -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. The list of email receivers that are part of this action group.') @@ -102,7 +102,7 @@ resource actionGroup 'Microsoft.Insights/actionGroups@2023-01-01' = { resource actionGroup_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(actionGroup.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -130,7 +130,7 @@ output location string = actionGroup.location // ================ // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/insights/action-group/main.json b/avm/res/insights/action-group/main.json index fb61030978..61d85daee7 100644 --- a/avm/res/insights/action-group/main.json +++ b/avm/res/insights/action-group/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "6349536763330820602" + "templateHash": "1880569328458125076" }, "name": "Action Groups", "description": "This module deploys an Action Group.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -103,7 +103,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "emailReceivers": { @@ -259,7 +259,7 @@ "scope": "[format('Microsoft.Insights/actionGroups/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Insights/actionGroups', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/insights/action-group/tests/e2e/defaults/main.test.bicep b/avm/res/insights/action-group/tests/e2e/defaults/main.test.bicep index 6a13769772..74b8c95346 100644 --- a/avm/res/insights/action-group/tests/e2e/defaults/main.test.bicep +++ b/avm/res/insights/action-group/tests/e2e/defaults/main.test.bicep @@ -43,19 +43,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: '${namePrefix}${serviceShort}001' location: 'global' groupShortName: 'ag${serviceShort}001' - - // Workaround for PSRule - tags: null - roleAssignments: null - emailReceivers: null - smsReceivers: null - webhookReceivers: null - itsmReceivers: null - azureAppPushReceivers: null - automationRunbookReceivers: null - voiceReceivers: null - logicAppReceivers: null - azureFunctionReceivers: null - armRoleReceivers: null } }] diff --git a/avm/res/insights/action-group/tests/e2e/max/main.test.bicep b/avm/res/insights/action-group/tests/e2e/max/main.test.bicep index 9148ebcf51..82b49b4d96 100644 --- a/avm/res/insights/action-group/tests/e2e/max/main.test.bicep +++ b/avm/res/insights/action-group/tests/e2e/max/main.test.bicep @@ -66,7 +66,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/insights/action-group/tests/e2e/waf-aligned/main.test.bicep b/avm/res/insights/action-group/tests/e2e/waf-aligned/main.test.bicep index c222ce383a..5f6bf02914 100644 --- a/avm/res/insights/action-group/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/insights/action-group/tests/e2e/waf-aligned/main.test.bicep @@ -57,17 +57,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Environment: 'Non-Prod' Role: 'DeploymentValidation' } - // Workaround for PSRule - emailReceivers: null - smsReceivers: null - webhookReceivers: null - itsmReceivers: null - azureAppPushReceivers: null - automationRunbookReceivers: null - voiceReceivers: null - logicAppReceivers: null - azureFunctionReceivers: null - armRoleReceivers: null - roleAssignments: null } }] diff --git a/avm/res/insights/component/README.md b/avm/res/insights/component/README.md index e4fc436991..66c0b88c7d 100644 --- a/avm/res/insights/component/README.md +++ b/avm/res/insights/component/README.md @@ -118,7 +118,17 @@ module component 'br/public:avm/res/insights/component:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] tags: { @@ -174,7 +184,17 @@ module component 'br/public:avm/res/insights/component:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -308,7 +328,7 @@ module component 'br/public:avm/res/insights/component:' = { | [`publicNetworkAccessForIngestion`](#parameter-publicnetworkaccessforingestion) | string | The network access type for accessing Application Insights ingestion. - Enabled or Disabled. | | [`publicNetworkAccessForQuery`](#parameter-publicnetworkaccessforquery) | string | The network access type for accessing Application Insights query. - Enabled or Disabled. | | [`retentionInDays`](#parameter-retentionindays) | int | Retention period in days. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`samplingPercentage`](#parameter-samplingpercentage) | int | Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry. | | [`tags`](#parameter-tags) | object | Tags of the resource. | @@ -519,7 +539,7 @@ Retention period in days. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -532,7 +552,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -580,7 +600,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/insights/component/main.bicep b/avm/res/insights/component/main.bicep index b3107a354f..82bd111b63 100644 --- a/avm/res/insights/component/main.bicep +++ b/avm/res/insights/component/main.bicep @@ -54,7 +54,7 @@ param kind string = '' @description('Optional. Location for all Resources.') param location string = resourceGroup().location -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. Tags of the resource.') @@ -110,7 +110,7 @@ resource appInsights 'Microsoft.Insights/components@2020-02-02' = { resource appInsights_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(appInsights.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -170,7 +170,7 @@ output instrumentationKey string = appInsights.properties.InstrumentationKey // =============== // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/insights/component/main.json b/avm/res/insights/component/main.json index 2dac3f14ec..be6bc4e026 100644 --- a/avm/res/insights/component/main.json +++ b/avm/res/insights/component/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "12168490973089144104" + "templateHash": "3523829055920723172" }, "name": "Application Insights", "description": "This component deploys an Application Insights instance.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -276,7 +276,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -356,7 +356,7 @@ "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Insights/components', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/insights/component/tests/e2e/max/main.test.bicep b/avm/res/insights/component/tests/e2e/max/main.test.bicep index 82669104b9..3051b15c84 100644 --- a/avm/res/insights/component/tests/e2e/max/main.test.bicep +++ b/avm/res/insights/component/tests/e2e/max/main.test.bicep @@ -81,7 +81,17 @@ module testDeployment '../../../main.bicep' = { ] roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/key-vault/vault/README.md b/avm/res/key-vault/vault/README.md index c87d3bb406..8a77180d71 100644 --- a/avm/res/key-vault/vault/README.md +++ b/avm/res/key-vault/vault/README.md @@ -55,17 +55,8 @@ module vault 'br/public:avm/res/key-vault/vault:' = { // Required parameters name: 'kvvmin002' // Non-required parameters - accessPolicies: [] - diagnosticSettings: [] enablePurgeProtection: false - keys: [] location: '' - lock: {} - networkAcls: {} - privateEndpoints: [] - roleAssignments: [] - secrets: {} - tags: {} } } ``` @@ -82,41 +73,16 @@ module vault 'br/public:avm/res/key-vault/vault:' = { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { + // Required parameters "name": { "value": "kvvmin002" }, - "accessPolicies": { - "value": [] - }, - "diagnosticSettings": { - "value": [] - }, + // Non-required parameters "enablePurgeProtection": { "value": false }, - "keys": { - "value": [] - }, "location": { "value": "" - }, - "lock": { - "value": {} - }, - "networkAcls": { - "value": {} - }, - "privateEndpoints": { - "value": [] - }, - "roleAssignments": { - "value": [] - }, - "secrets": { - "value": {} - }, - "tags": { - "value": {} } } } @@ -209,7 +175,17 @@ module vault 'br/public:avm/res/key-vault/vault:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] rotationPolicy: { @@ -266,7 +242,12 @@ module vault 'br/public:avm/res/key-vault/vault:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] service: 'vault' @@ -282,7 +263,17 @@ module vault 'br/public:avm/res/key-vault/vault:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] secrets: { @@ -296,7 +287,17 @@ module vault 'br/public:avm/res/key-vault/vault:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] value: 'secretValue' @@ -405,7 +406,17 @@ module vault 'br/public:avm/res/key-vault/vault:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "rotationPolicy": { @@ -470,7 +481,12 @@ module vault 'br/public:avm/res/key-vault/vault:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "service": "vault", @@ -488,7 +504,17 @@ module vault 'br/public:avm/res/key-vault/vault:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -504,7 +530,17 @@ module vault 'br/public:avm/res/key-vault/vault:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "value": "secretValue" @@ -637,7 +673,6 @@ module vault 'br/public:avm/res/key-vault/vault:' = { // Required parameters name: 'kvvwaf002' // Non-required parameters - accessPolicies: [] diagnosticSettings: [ { eventHubAuthorizationRuleResourceId: '' @@ -697,7 +732,6 @@ module vault 'br/public:avm/res/key-vault/vault:' = { subnetResourceId: '' } ] - roleAssignments: [] secrets: { secureList: [ { @@ -734,9 +768,6 @@ module vault 'br/public:avm/res/key-vault/vault:' = { "name": { "value": "kvvwaf002" }, - "accessPolicies": { - "value": [] - }, "diagnosticSettings": { "value": [ { @@ -812,9 +843,6 @@ module vault 'br/public:avm/res/key-vault/vault:' = { } ] }, - "roleAssignments": { - "value": [] - }, "secrets": { "value": { "secureList": [ @@ -874,7 +902,7 @@ module vault 'br/public:avm/res/key-vault/vault:' = { | [`networkAcls`](#parameter-networkacls) | object | Rules governing the accessibility of the resouce from specific network locations. | | [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | | [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | 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`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`secrets`](#parameter-secrets) | secureObject | All secrets to create. | | [`sku`](#parameter-sku) | string | Specifies the SKU for the vault. | | [`softDeleteRetentionInDays`](#parameter-softdeleteretentionindays) | int | softDelete data retention days. It accepts >=7 and <=90. | @@ -1202,7 +1230,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | No | string | Optional. The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | No | string | Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | No | array | Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | -| [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | array | 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'. | +| [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | array | Optional. Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | No | string | Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | | [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | Yes | string | Required. Resource ID of the subnet where the endpoint needs to be created. | | [`tags`](#parameter-privateendpointstags) | No | object | Optional. Tags to be applied on all resources/resource groups in this deployment. | @@ -1324,7 +1352,7 @@ Optional. The private DNS zone groups to associate the private endpoint with. A ### Parameter: `privateEndpoints.roleAssignments` -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'. +Optional. Array of role assignments to create. - Required: No - Type: array @@ -1367,7 +1395,7 @@ Whether or not public network access is allowed for this resource. For security ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -1380,7 +1408,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -1428,7 +1456,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/key-vault/vault/access-policy/main.json b/avm/res/key-vault/vault/access-policy/main.json index afeab4a10b..f2a4aa32b9 100644 --- a/avm/res/key-vault/vault/access-policy/main.json +++ b/avm/res/key-vault/vault/access-policy/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "16565480734433924198" + "version": "0.23.1.45101", + "templateHash": "3185669298547069044" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", diff --git a/avm/res/key-vault/vault/key/README.md b/avm/res/key-vault/vault/key/README.md index 9e9e56a4cb..2a46c1e861 100644 --- a/avm/res/key-vault/vault/key/README.md +++ b/avm/res/key-vault/vault/key/README.md @@ -41,7 +41,7 @@ This module deploys a Key Vault Key. | [`keyOps`](#parameter-keyops) | array | Array of JsonWebKeyOperation. | | [`keySize`](#parameter-keysize) | int | The key size in bits. For example: 2048, 3072, or 4096 for RSA. | | [`kty`](#parameter-kty) | string | The type of the key. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`rotationPolicy`](#parameter-rotationpolicy) | object | Key rotation policy properties object. | | [`tags`](#parameter-tags) | object | Resource tags. | @@ -134,7 +134,7 @@ The name of the key. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -147,7 +147,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -195,7 +195,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/key-vault/vault/key/main.bicep b/avm/res/key-vault/vault/key/main.bicep index 4a5807f4e8..cf9d53037d 100644 --- a/avm/res/key-vault/vault/key/main.bicep +++ b/avm/res/key-vault/vault/key/main.bicep @@ -53,7 +53,7 @@ param keySize int? ]) param kty string = 'EC' -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. Key rotation policy properties object.') @@ -101,7 +101,7 @@ resource key 'Microsoft.KeyVault/vaults/keys@2022-07-01' = { resource key_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(key.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -126,7 +126,7 @@ output resourceGroupName string = resourceGroup().name // ================ // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/key-vault/vault/key/main.json b/avm/res/key-vault/vault/key/main.json index 7ea489a81b..9b4008e4c8 100644 --- a/avm/res/key-vault/vault/key/main.json +++ b/avm/res/key-vault/vault/key/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "10926648479875609377" + "version": "0.23.1.45101", + "templateHash": "18051755205410983972" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -173,7 +173,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "rotationPolicy": { @@ -240,7 +240,7 @@ "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', parameters('keyVaultName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/key-vault/vault/main.bicep b/avm/res/key-vault/vault/main.bicep index 3dff6ecf6c..c07ffa48ba 100644 --- a/avm/res/key-vault/vault/main.bicep +++ b/avm/res/key-vault/vault/main.bicep @@ -67,7 +67,7 @@ param publicNetworkAccess string = '' @description('Optional. The lock settings of the service.') param lock lockType -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') @@ -266,7 +266,7 @@ module keyVault_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.2 resource keyVault_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(keyVault.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -338,7 +338,7 @@ type diagnosticSettingType = { }[]? type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') @@ -403,7 +403,7 @@ type privateEndpointType = { @description('Optional. Specify the type of lock.') lock: lockType - @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\'.') + @description('Optional. Array of role assignments to create.') roleAssignments: roleAssignmentType @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index 4f1aa9e271..b9a9f93646 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "15892116294747624679" + "version": "0.23.1.45101", + "templateHash": "665865372091259296" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -127,7 +127,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -306,7 +306,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -622,7 +622,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "privateEndpoints": { @@ -776,7 +776,7 @@ "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.KeyVault/vaults', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -813,8 +813,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "16565480734433924198" + "version": "0.23.1.45101", + "templateHash": "3185669298547069044" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", @@ -1079,8 +1079,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "16336835405945824329" + "version": "0.23.1.45101", + "templateHash": "14810918598323806738" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", @@ -1095,7 +1095,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -1211,7 +1211,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -1268,7 +1268,7 @@ "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -1368,8 +1368,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "10926648479875609377" + "version": "0.23.1.45101", + "templateHash": "18051755205410983972" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", @@ -1384,7 +1384,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -1536,7 +1536,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "rotationPolicy": { @@ -1603,7 +1603,7 @@ "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', parameters('keyVaultName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/key-vault/vault/secret/README.md b/avm/res/key-vault/vault/secret/README.md index 0b7ae5677b..1c8e6498a7 100644 --- a/avm/res/key-vault/vault/secret/README.md +++ b/avm/res/key-vault/vault/secret/README.md @@ -39,7 +39,7 @@ This module deploys a Key Vault Secret. | [`attributesExp`](#parameter-attributesexp) | int | Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible. | | [`attributesNbf`](#parameter-attributesnbf) | int | Not before date in seconds since 1970-01-01T00:00:00Z. | | [`contentType`](#parameter-contenttype) | securestring | The content type of the secret. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`tags`](#parameter-tags) | object | Resource tags. | ### Parameter: `attributesEnabled` @@ -81,7 +81,7 @@ The name of the secret. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -94,7 +94,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -142,7 +142,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/key-vault/vault/secret/main.bicep b/avm/res/key-vault/vault/secret/main.bicep index 0d4ea3dc2c..19468a83e4 100644 --- a/avm/res/key-vault/vault/secret/main.bicep +++ b/avm/res/key-vault/vault/secret/main.bicep @@ -28,7 +28,7 @@ param contentType string? @secure() param value 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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -70,7 +70,7 @@ resource secret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { resource secret_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(secret.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -95,7 +95,7 @@ output resourceGroupName string = resourceGroup().name // ================ // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/key-vault/vault/secret/main.json b/avm/res/key-vault/vault/secret/main.json index b62da35740..2b87479bd6 100644 --- a/avm/res/key-vault/vault/secret/main.json +++ b/avm/res/key-vault/vault/secret/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "16336835405945824329" + "version": "0.23.1.45101", + "templateHash": "14810918598323806738" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -137,7 +137,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -194,7 +194,7 @@ "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/key-vault/vault/tests/e2e/defaults/main.test.bicep b/avm/res/key-vault/vault/tests/e2e/defaults/main.test.bicep index 48026d8979..8297b5cf1d 100644 --- a/avm/res/key-vault/vault/tests/e2e/defaults/main.test.bicep +++ b/avm/res/key-vault/vault/tests/e2e/defaults/main.test.bicep @@ -47,15 +47,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' location: location // Only for testing purposes enablePurgeProtection: false - // Workaround for PSRule - lock: {} - roleAssignments: [] - diagnosticSettings: [] - privateEndpoints: [] - networkAcls: {} - accessPolicies: [] - secrets: {} - keys: [] - tags: {} } }] diff --git a/avm/res/key-vault/vault/tests/e2e/max/main.test.bicep b/avm/res/key-vault/vault/tests/e2e/max/main.test.bicep index 035d80a19c..5827070e98 100644 --- a/avm/res/key-vault/vault/tests/e2e/max/main.test.bicep +++ b/avm/res/key-vault/vault/tests/e2e/max/main.test.bicep @@ -133,7 +133,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: 'keyName' roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -196,7 +206,12 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' } roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -205,7 +220,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -219,7 +244,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: 'secretName' roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/key-vault/vault/tests/e2e/waf-aligned/main.test.bicep b/avm/res/key-vault/vault/tests/e2e/waf-aligned/main.test.bicep index 45c930e01b..0cd1ec7bd8 100644 --- a/avm/res/key-vault/vault/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/key-vault/vault/tests/e2e/waf-aligned/main.test.bicep @@ -142,8 +142,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Environment: 'Non-Prod' Role: 'DeploymentValidation' } - // Workaround for PSRule - roleAssignments: [] - accessPolicies: [] } }] diff --git a/avm/res/kubernetes-configuration/extension/README.md b/avm/res/kubernetes-configuration/extension/README.md index 1f922bec71..5d1897658b 100644 --- a/avm/res/kubernetes-configuration/extension/README.md +++ b/avm/res/kubernetes-configuration/extension/README.md @@ -50,14 +50,9 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension: extensionType: 'microsoft.flux' name: 'kcemin001' // Non-required parameters - configurationProtectedSettings: '' - configurationSettings: '' - fluxConfigurations: '' location: '' releaseNamespace: 'flux-system' releaseTrain: 'Stable' - targetNamespace: '' - version: '' } } ``` @@ -85,15 +80,6 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension: "value": "kcemin001" }, // Non-required parameters - "configurationProtectedSettings": { - "value": "" - }, - "configurationSettings": { - "value": "" - }, - "fluxConfigurations": { - "value": "" - }, "location": { "value": "" }, @@ -102,12 +88,6 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension: }, "releaseTrain": { "value": "Stable" - }, - "targetNamespace": { - "value": "" - }, - "version": { - "value": "" } } } @@ -134,7 +114,6 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension: extensionType: 'microsoft.flux' name: 'kcemax001' // Non-required parameters - configurationProtectedSettings: '' configurationSettings: { 'image-automation-controller.enabled': 'false' 'image-reflector-controller.enabled': 'false' @@ -165,7 +144,6 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension: location: '' releaseNamespace: 'flux-system' releaseTrain: 'Stable' - targetNamespace: '' version: '0.5.2' } } @@ -194,9 +172,6 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension: "value": "kcemax001" }, // Non-required parameters - "configurationProtectedSettings": { - "value": "" - }, "configurationSettings": { "value": { "image-automation-controller.enabled": "false", @@ -237,9 +212,6 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension: "releaseTrain": { "value": "Stable" }, - "targetNamespace": { - "value": "" - }, "version": { "value": "0.5.2" } @@ -268,7 +240,6 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension: extensionType: 'microsoft.flux' name: 'kcewaf001' // Non-required parameters - configurationProtectedSettings: '' configurationSettings: { 'image-automation-controller.enabled': 'false' 'image-reflector-controller.enabled': 'false' @@ -299,7 +270,6 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension: location: '' releaseNamespace: 'flux-system' releaseTrain: 'Stable' - targetNamespace: '' version: '0.5.2' } } @@ -328,9 +298,6 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension: "value": "kcewaf001" }, // Non-required parameters - "configurationProtectedSettings": { - "value": "" - }, "configurationSettings": { "value": { "image-automation-controller.enabled": "false", @@ -371,9 +338,6 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension: "releaseTrain": { "value": "Stable" }, - "targetNamespace": { - "value": "" - }, "version": { "value": "0.5.2" } diff --git a/avm/res/kubernetes-configuration/extension/tests/e2e/defaults/main.test.bicep b/avm/res/kubernetes-configuration/extension/tests/e2e/defaults/main.test.bicep index 4e65c21a6b..27e1da7346 100644 --- a/avm/res/kubernetes-configuration/extension/tests/e2e/defaults/main.test.bicep +++ b/avm/res/kubernetes-configuration/extension/tests/e2e/defaults/main.test.bicep @@ -58,11 +58,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' extensionType: 'microsoft.flux' releaseNamespace: 'flux-system' releaseTrain: 'Stable' - // Workaround for PSRule - fluxConfigurations: null - version: null - configurationProtectedSettings: null - configurationSettings: null - targetNamespace: null } }] diff --git a/avm/res/kubernetes-configuration/extension/tests/e2e/max/main.test.bicep b/avm/res/kubernetes-configuration/extension/tests/e2e/max/main.test.bicep index 73d08bb3ae..5a11a6257b 100644 --- a/avm/res/kubernetes-configuration/extension/tests/e2e/max/main.test.bicep +++ b/avm/res/kubernetes-configuration/extension/tests/e2e/max/main.test.bicep @@ -85,8 +85,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' suspend: false } ] - // Workaround for PSRule - configurationProtectedSettings: null - targetNamespace: null } }] diff --git a/avm/res/kubernetes-configuration/extension/tests/e2e/waf-aligned/main.test.bicep b/avm/res/kubernetes-configuration/extension/tests/e2e/waf-aligned/main.test.bicep index 7514a02f72..f46741cde8 100644 --- a/avm/res/kubernetes-configuration/extension/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/kubernetes-configuration/extension/tests/e2e/waf-aligned/main.test.bicep @@ -85,8 +85,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' suspend: false } ] - // Workaround for PSRule - configurationProtectedSettings: null - targetNamespace: null } }] diff --git a/avm/res/kubernetes-configuration/flux-configuration/README.md b/avm/res/kubernetes-configuration/flux-configuration/README.md index 8ca0ad8ee4..867b58e825 100644 --- a/avm/res/kubernetes-configuration/flux-configuration/README.md +++ b/avm/res/kubernetes-configuration/flux-configuration/README.md @@ -55,8 +55,6 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config namespace: 'flux-system' sourceKind: 'GitRepository' // Non-required parameters - bucket: '' - configurationProtectedSettings: '' gitRepository: { repositoryRef: { branch: 'main' @@ -104,12 +102,6 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config "value": "GitRepository" }, // Non-required parameters - "bucket": { - "value": "" - }, - "configurationProtectedSettings": { - "value": "" - }, "gitRepository": { "value": { "repositoryRef": { @@ -166,8 +158,6 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config namespace: 'flux-system' sourceKind: 'GitRepository' // Non-required parameters - bucket: '' - configurationProtectedSettings: '' gitRepository: { repositoryRef: { branch: 'main' @@ -226,12 +216,6 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config "value": "GitRepository" }, // Non-required parameters - "bucket": { - "value": "" - }, - "configurationProtectedSettings": { - "value": "" - }, "gitRepository": { "value": { "repositoryRef": { @@ -282,8 +266,6 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config namespace: 'flux-system' sourceKind: 'GitRepository' // Non-required parameters - bucket: '' - configurationProtectedSettings: '' gitRepository: { repositoryRef: { branch: 'main' @@ -336,12 +318,6 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config "value": "GitRepository" }, // Non-required parameters - "bucket": { - "value": "" - }, - "configurationProtectedSettings": { - "value": "" - }, "gitRepository": { "value": { "repositoryRef": { diff --git a/avm/res/kubernetes-configuration/flux-configuration/tests/e2e/defaults/main.test.bicep b/avm/res/kubernetes-configuration/flux-configuration/tests/e2e/defaults/main.test.bicep index 2875d233e7..4b195f6b1a 100644 --- a/avm/res/kubernetes-configuration/flux-configuration/tests/e2e/defaults/main.test.bicep +++ b/avm/res/kubernetes-configuration/flux-configuration/tests/e2e/defaults/main.test.bicep @@ -74,8 +74,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' path: './cluster-manifests' } } - // Workaround for PSRule - bucket: null - configurationProtectedSettings: null } }] diff --git a/avm/res/kubernetes-configuration/flux-configuration/tests/e2e/max/main.test.bicep b/avm/res/kubernetes-configuration/flux-configuration/tests/e2e/max/main.test.bicep index 06ff65561f..872304fe85 100644 --- a/avm/res/kubernetes-configuration/flux-configuration/tests/e2e/max/main.test.bicep +++ b/avm/res/kubernetes-configuration/flux-configuration/tests/e2e/max/main.test.bicep @@ -82,8 +82,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' } } } - // Workaround for PSRule - bucket: null - configurationProtectedSettings: null } }] diff --git a/avm/res/kubernetes-configuration/flux-configuration/tests/e2e/waf-aligned/main.test.bicep b/avm/res/kubernetes-configuration/flux-configuration/tests/e2e/waf-aligned/main.test.bicep index 1ddeb73b37..475cdc867f 100644 --- a/avm/res/kubernetes-configuration/flux-configuration/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/kubernetes-configuration/flux-configuration/tests/e2e/waf-aligned/main.test.bicep @@ -76,8 +76,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' timeoutInSeconds: 300 } } - // Workaround for PSRule - bucket: null - configurationProtectedSettings: null } }] diff --git a/avm/res/logic/workflow/README.md b/avm/res/logic/workflow/README.md index 93cd0fe6b3..ab819e81dc 100644 --- a/avm/res/logic/workflow/README.md +++ b/avm/res/logic/workflow/README.md @@ -51,9 +51,6 @@ module workflow 'br/public:avm/res/logic/workflow:' = { name: 'lwmin001' // Non-required parameters location: '' - lock: '' - roleAssignments: '' - tags: {} } } ``` @@ -77,15 +74,6 @@ module workflow 'br/public:avm/res/logic/workflow:' = { // Non-required parameters "location": { "value": "" - }, - "lock": { - "value": "" - }, - "roleAssignments": { - "value": "" - }, - "tags": { - "value": {} } } } @@ -138,7 +126,17 @@ module workflow 'br/public:avm/res/logic/workflow:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] tags: { @@ -235,7 +233,17 @@ module workflow 'br/public:avm/res/logic/workflow:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -490,7 +498,7 @@ module workflow 'br/public:avm/res/logic/workflow:' = { | [`location`](#parameter-location) | string | Location for all resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | | [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`state`](#parameter-state) | string | The state. - NotSpecified, Completed, Enabled, Disabled, Deleted, Suspended. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`triggersAccessControlConfiguration`](#parameter-triggersaccesscontrolconfiguration) | object | The access control configuration for invoking workflow triggers. | @@ -740,7 +748,7 @@ The logic app workflow name. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -753,7 +761,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -801,7 +809,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/logic/workflow/main.bicep b/avm/res/logic/workflow/main.bicep index 49b70f2aa0..7143d9e190 100644 --- a/avm/res/logic/workflow/main.bicep +++ b/avm/res/logic/workflow/main.bicep @@ -38,7 +38,7 @@ param diagnosticSettings diagnosticSettingType @description('Optional. The lock settings of the service.') param lock lockType -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. The state. - NotSpecified, Completed, Enabled, Disabled, Deleted, Suspended.') @@ -184,7 +184,7 @@ resource logicApp_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021 resource logicApp_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(logicApp.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -274,7 +274,7 @@ type managedIdentitiesType = { }? type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/logic/workflow/main.json b/avm/res/logic/workflow/main.json index 1c38736edb..926baadd3e 100644 --- a/avm/res/logic/workflow/main.json +++ b/avm/res/logic/workflow/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "2823647560505924918" + "templateHash": "6187978645614326475" }, "name": "Logic Apps (Workflows)", "description": "This module deploys a Logic App (Workflow).", @@ -188,7 +188,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -331,7 +331,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "state": { @@ -527,7 +527,7 @@ "scope": "[format('Microsoft.Logic/workflows/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Logic/workflows', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/logic/workflow/tests/e2e/defaults/main.test.bicep b/avm/res/logic/workflow/tests/e2e/defaults/main.test.bicep index 1fba5ecf0a..c48184ea65 100644 --- a/avm/res/logic/workflow/tests/e2e/defaults/main.test.bicep +++ b/avm/res/logic/workflow/tests/e2e/defaults/main.test.bicep @@ -45,9 +45,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' params: { name: '${namePrefix}${serviceShort}001' location: location - // Workaround for PSRule - lock: null - roleAssignments: null - tags: {} } }] diff --git a/avm/res/logic/workflow/tests/e2e/max/main.test.bicep b/avm/res/logic/workflow/tests/e2e/max/main.test.bicep index b16f072d6f..d205faf768 100644 --- a/avm/res/logic/workflow/tests/e2e/max/main.test.bicep +++ b/avm/res/logic/workflow/tests/e2e/max/main.test.bicep @@ -85,7 +85,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' } roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/network/dns-forwarding-ruleset/README.md b/avm/res/network/dns-forwarding-ruleset/README.md index 7e0360e4bf..8106f0893b 100644 --- a/avm/res/network/dns-forwarding-ruleset/README.md +++ b/avm/res/network/dns-forwarding-ruleset/README.md @@ -53,12 +53,7 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset:' - lock: {} - roleAssignments: [] - tags: {} - vNetLinks: [] } } ``` @@ -85,23 +80,8 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset:" - }, - "lock": { - "value": {} - }, - "roleAssignments": { - "value": [] - }, - "tags": { - "value": {} - }, - "vNetLinks": { - "value": [] } } } @@ -151,7 +131,17 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset:' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] tags: { @@ -217,7 +207,17 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset:", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -259,19 +259,16 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset:' lock: { kind: 'CanNotDelete' name: 'myCustomLockName' } - roleAssignments: [] tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - vNetLinks: [] } } ``` @@ -298,9 +295,6 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset:" }, @@ -310,18 +304,12 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset:' = { name: 'ndrmin001' virtualNetworkResourceId: '' // Non-required parameters - inboundEndpoints: [] location: '' - lock: {} - outboundEndpoints: [] - roleAssignments: [] - tags: {} } } ``` @@ -81,23 +76,8 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = { "value": "" }, // Non-required parameters - "inboundEndpoints": { - "value": [] - }, "location": { "value": "" - }, - "lock": { - "value": {} - }, - "outboundEndpoints": { - "value": [] - }, - "roleAssignments": { - "value": [] - }, - "tags": { - "value": {} } } } @@ -144,7 +124,17 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] tags: { @@ -206,7 +196,17 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -258,7 +258,6 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = { subnetResourceId: '' } ] - roleAssignments: [] tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -313,9 +312,6 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = { } ] }, - "roleAssignments": { - "value": [] - }, "tags": { "value": { "Environment": "Non-Prod", @@ -349,7 +345,7 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = { | [`location`](#parameter-location) | string | Location for all resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | | [`outboundEndpoints`](#parameter-outboundendpoints) | array | Outbound Endpoints for Private DNS Resolver. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`tags`](#parameter-tags) | object | Tags of the resource. | ### Parameter: `enableTelemetry` @@ -413,7 +409,7 @@ Outbound Endpoints for Private DNS Resolver. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -426,7 +422,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -474,7 +470,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/dns-resolver/main.bicep b/avm/res/network/dns-resolver/main.bicep index cab4598b8e..e4adaa979b 100644 --- a/avm/res/network/dns-resolver/main.bicep +++ b/avm/res/network/dns-resolver/main.bicep @@ -12,7 +12,7 @@ param location string = resourceGroup().location @description('Optional. The lock settings of the service.') param lock lockType -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. Tags of the resource.') @@ -84,7 +84,7 @@ resource dnsResolver_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empt resource dnsResolver_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(dnsResolver.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -137,7 +137,7 @@ output location string = dnsResolver.location // ================ // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/dns-resolver/main.json b/avm/res/network/dns-resolver/main.json index 86e4f31f68..7de54511ba 100644 --- a/avm/res/network/dns-resolver/main.json +++ b/avm/res/network/dns-resolver/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "8204369866925392451" + "templateHash": "9457647072008128040" }, "name": "DNS Resolvers", "description": "This module deploys a DNS Resolver.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -129,7 +129,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -238,7 +238,7 @@ "scope": "[format('Microsoft.Network/dnsResolvers/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsResolvers', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/dns-resolver/tests/e2e/defaults/main.test.bicep b/avm/res/network/dns-resolver/tests/e2e/defaults/main.test.bicep index bb2e30fe01..aff32456f8 100644 --- a/avm/res/network/dns-resolver/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/dns-resolver/tests/e2e/defaults/main.test.bicep @@ -56,12 +56,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: '${namePrefix}${serviceShort}001' virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId location: location - - // Non-required parameters - Workaround for PS Rule - inboundEndpoints: [] - outboundEndpoints: [] - lock: {} - roleAssignments: [] - tags: {} } }] diff --git a/avm/res/network/dns-resolver/tests/e2e/max/main.test.bicep b/avm/res/network/dns-resolver/tests/e2e/max/main.test.bicep index 68ee0bbb5a..66818b0a24 100644 --- a/avm/res/network/dns-resolver/tests/e2e/max/main.test.bicep +++ b/avm/res/network/dns-resolver/tests/e2e/max/main.test.bicep @@ -59,7 +59,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' } roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/network/dns-resolver/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/dns-resolver/tests/e2e/waf-aligned/main.test.bicep index 4fea076053..4070b4cc6e 100644 --- a/avm/res/network/dns-resolver/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/dns-resolver/tests/e2e/waf-aligned/main.test.bicep @@ -74,7 +74,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Environment: 'Non-Prod' Role: 'DeploymentValidation' } - // Workaround for PSRule - roleAssignments: [] } }] diff --git a/avm/res/network/dns-zone/README.md b/avm/res/network/dns-zone/README.md index 96f839ea22..3c24bfaa0c 100644 --- a/avm/res/network/dns-zone/README.md +++ b/avm/res/network/dns-zone/README.md @@ -56,20 +56,7 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { // Required parameters name: 'ndzmin001.com' // Non-required parameters - a: [] - aaaa: [] - caa: [] - cname: [] location: 'global' - lock: {} - mx: [] - ns: [] - ptr: [] - roleAssignments: [] - soa: [] - srv: [] - tags: {} - txt: [] } } ``` @@ -91,47 +78,8 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { "value": "ndzmin001.com" }, // Non-required parameters - "a": { - "value": [] - }, - "aaaa": { - "value": [] - }, - "caa": { - "value": [] - }, - "cname": { - "value": [] - }, "location": { "value": "global" - }, - "lock": { - "value": {} - }, - "mx": { - "value": [] - }, - "ns": { - "value": [] - }, - "ptr": { - "value": [] - }, - "roleAssignments": { - "value": [] - }, - "soa": { - "value": [] - }, - "srv": { - "value": [] - }, - "tags": { - "value": {} - }, - "txt": { - "value": [] } } } @@ -168,7 +116,17 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] ttl: 3600 @@ -195,7 +153,17 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] ttl: 3600 @@ -223,7 +191,17 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] ttl: 3600 @@ -241,7 +219,17 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] ttl: 3600 @@ -251,7 +239,17 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] soa: [ @@ -261,7 +259,17 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] soaRecord: { @@ -283,7 +291,17 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] srvRecords: [ @@ -309,7 +327,17 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] ttl: 3600 @@ -356,7 +384,17 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "ttl": 3600 @@ -387,7 +425,17 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "ttl": 3600 @@ -421,7 +469,17 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "ttl": 3600 @@ -441,7 +499,17 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "ttl": 3600 @@ -453,7 +521,17 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -465,7 +543,17 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "soaRecord": { @@ -489,7 +577,17 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "srvRecords": [ @@ -519,7 +617,17 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "ttl": 3600, @@ -556,25 +664,16 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { // Required parameters name: 'ndzwaf001.com' // Non-required parameters - a: [] - aaaa: [] - cname: [] location: 'global' lock: { kind: 'CanNotDelete' name: 'myCustomLockName' } - mx: [] - ptr: [] - roleAssignments: [] - soa: [] - srv: [] tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - txt: [] } } ``` @@ -596,15 +695,6 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { "value": "ndzwaf001.com" }, // Non-required parameters - "a": { - "value": [] - }, - "aaaa": { - "value": [] - }, - "cname": { - "value": [] - }, "location": { "value": "global" }, @@ -614,30 +704,12 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { "name": "myCustomLockName" } }, - "mx": { - "value": [] - }, - "ptr": { - "value": [] - }, - "roleAssignments": { - "value": [] - }, - "soa": { - "value": [] - }, - "srv": { - "value": [] - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "txt": { - "value": [] } } } @@ -669,7 +741,7 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = { | [`mx`](#parameter-mx) | array | Array of MX records. | | [`ns`](#parameter-ns) | array | Array of NS records. | | [`ptr`](#parameter-ptr) | array | Array of PTR records. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`soa`](#parameter-soa) | array | Array of SOA records. | | [`srv`](#parameter-srv) | array | Array of SRV records. | | [`tags`](#parameter-tags) | object | Tags of the resource. | @@ -766,7 +838,7 @@ Array of PTR records. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -779,7 +851,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -827,7 +899,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/dns-zone/a/README.md b/avm/res/network/dns-zone/a/README.md index af80235133..a0757aecc6 100644 --- a/avm/res/network/dns-zone/a/README.md +++ b/avm/res/network/dns-zone/a/README.md @@ -36,7 +36,7 @@ This module deploys a Public DNS Zone A record. | :-- | :-- | :-- | | [`aRecords`](#parameter-arecords) | array | The list of A records in the record set. Cannot be used in conjuction with the "targetResource" property. | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`targetResourceId`](#parameter-targetresourceid) | string | A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | @@ -66,7 +66,7 @@ The name of the A record. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -79,7 +79,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -127,7 +127,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/dns-zone/a/main.bicep b/avm/res/network/dns-zone/a/main.bicep index aaa83d1bd2..0c53caac2a 100644 --- a/avm/res/network/dns-zone/a/main.bicep +++ b/avm/res/network/dns-zone/a/main.bicep @@ -20,7 +20,7 @@ param ttl int = 3600 @description('Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property.') param targetResourceId 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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -56,7 +56,7 @@ resource A 'Microsoft.Network/dnsZones/A@2018-05-01' = { resource A_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(A.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -80,7 +80,7 @@ output resourceGroupName string = resourceGroup().name // =============== // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/dns-zone/a/main.json b/avm/res/network/dns-zone/a/main.json index 0be98a8c95..fd52b73b1c 100644 --- a/avm/res/network/dns-zone/a/main.json +++ b/avm/res/network/dns-zone/a/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "5102357917037426899" + "templateHash": "12120328600933901484" }, "name": "Public DNS Zone A record", "description": "This module deploys a Public DNS Zone A record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -124,7 +124,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -174,7 +174,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/A/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/A', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/dns-zone/aaaa/README.md b/avm/res/network/dns-zone/aaaa/README.md index d511f2dff7..4da1e29078 100644 --- a/avm/res/network/dns-zone/aaaa/README.md +++ b/avm/res/network/dns-zone/aaaa/README.md @@ -36,7 +36,7 @@ This module deploys a Public DNS Zone AAAA record. | :-- | :-- | :-- | | [`aaaaRecords`](#parameter-aaaarecords) | array | The list of AAAA records in the record set. Cannot be used in conjuction with the "targetResource" property. | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`targetResourceId`](#parameter-targetresourceid) | string | A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | @@ -66,7 +66,7 @@ The name of the AAAA record. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -79,7 +79,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -127,7 +127,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/dns-zone/aaaa/main.bicep b/avm/res/network/dns-zone/aaaa/main.bicep index d8b7547d5e..168ad91756 100644 --- a/avm/res/network/dns-zone/aaaa/main.bicep +++ b/avm/res/network/dns-zone/aaaa/main.bicep @@ -20,7 +20,7 @@ param ttl int = 3600 @description('Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property.') param targetResourceId 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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -57,7 +57,7 @@ resource AAAA 'Microsoft.Network/dnsZones/AAAA@2018-05-01' = { resource AAAA_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(AAAA.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -81,7 +81,7 @@ output resourceGroupName string = resourceGroup().name // =============== // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/dns-zone/aaaa/main.json b/avm/res/network/dns-zone/aaaa/main.json index 722ba83c64..d309899736 100644 --- a/avm/res/network/dns-zone/aaaa/main.json +++ b/avm/res/network/dns-zone/aaaa/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "15377155277897248268" + "templateHash": "1358707556106672388" }, "name": "Public DNS Zone AAAA record", "description": "This module deploys a Public DNS Zone AAAA record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -124,7 +124,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -174,7 +174,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/AAAA/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/AAAA', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/dns-zone/caa/README.md b/avm/res/network/dns-zone/caa/README.md index d9028ac26a..7ecba4e317 100644 --- a/avm/res/network/dns-zone/caa/README.md +++ b/avm/res/network/dns-zone/caa/README.md @@ -36,7 +36,7 @@ This module deploys a Public DNS Zone CAA record. | :-- | :-- | :-- | | [`caaRecords`](#parameter-caarecords) | array | The list of CAA records in the record set. | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | ### Parameter: `caaRecords` @@ -65,7 +65,7 @@ The name of the CAA record. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -78,7 +78,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -126,7 +126,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/dns-zone/caa/main.bicep b/avm/res/network/dns-zone/caa/main.bicep index cdd3e29c1f..51c91817e8 100644 --- a/avm/res/network/dns-zone/caa/main.bicep +++ b/avm/res/network/dns-zone/caa/main.bicep @@ -17,7 +17,7 @@ param caaRecords array? @description('Optional. The TTL (time-to-live) of the records in the record set.') param ttl int = 3600 -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -51,7 +51,7 @@ resource CAA 'Microsoft.Network/dnsZones/CAA@2018-05-01' = { resource CAA_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(CAA.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -75,7 +75,7 @@ output resourceGroupName string = resourceGroup().name // =============== // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/dns-zone/caa/main.json b/avm/res/network/dns-zone/caa/main.json index 750b76af1c..237385bd46 100644 --- a/avm/res/network/dns-zone/caa/main.json +++ b/avm/res/network/dns-zone/caa/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "14137420953130091892" + "templateHash": "13353997192315697593" }, "name": "Public DNS Zone CAA record", "description": "This module deploys a Public DNS Zone CAA record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -117,7 +117,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -166,7 +166,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/CAA/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/CAA', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/dns-zone/cname/README.md b/avm/res/network/dns-zone/cname/README.md index 9d38465a88..42c859826b 100644 --- a/avm/res/network/dns-zone/cname/README.md +++ b/avm/res/network/dns-zone/cname/README.md @@ -36,7 +36,7 @@ This module deploys a Public DNS Zone CNAME record. | :-- | :-- | :-- | | [`cnameRecord`](#parameter-cnamerecord) | object | A CNAME record. Cannot be used in conjuction with the "targetResource" property. | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`targetResourceId`](#parameter-targetresourceid) | string | A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | @@ -66,7 +66,7 @@ The name of the CNAME record. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -79,7 +79,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -127,7 +127,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/dns-zone/cname/main.bicep b/avm/res/network/dns-zone/cname/main.bicep index ebb5f48043..2a1cd6fd06 100644 --- a/avm/res/network/dns-zone/cname/main.bicep +++ b/avm/res/network/dns-zone/cname/main.bicep @@ -20,7 +20,7 @@ param ttl int = 3600 @description('Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property.') param targetResourceId 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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -57,7 +57,7 @@ resource CNAME 'Microsoft.Network/dnsZones/CNAME@2018-05-01' = { resource CNAME_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(CNAME.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -81,7 +81,7 @@ output resourceGroupName string = resourceGroup().name // =============== // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/dns-zone/cname/main.json b/avm/res/network/dns-zone/cname/main.json index d730668667..ab4ecfcd4b 100644 --- a/avm/res/network/dns-zone/cname/main.json +++ b/avm/res/network/dns-zone/cname/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "15202379687273336739" + "templateHash": "2252647874269685796" }, "name": "Public DNS Zone CNAME record", "description": "This module deploys a Public DNS Zone CNAME record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -124,7 +124,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -174,7 +174,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/CNAME/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/CNAME', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/dns-zone/main.bicep b/avm/res/network/dns-zone/main.bicep index 44b52e5f9c..fa78e7797d 100644 --- a/avm/res/network/dns-zone/main.bicep +++ b/avm/res/network/dns-zone/main.bicep @@ -40,7 +40,7 @@ param txt array? @description('Optional. The location of the dnsZone. Should be global.') param location string = 'global' -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. Tags of the resource.') @@ -228,7 +228,7 @@ resource dnsZone_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lo resource dnsZone_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(dnsZone.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -264,7 +264,7 @@ type lockType = { }? type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/dns-zone/main.json b/avm/res/network/dns-zone/main.json index 306d01aff2..48a8a7e218 100644 --- a/avm/res/network/dns-zone/main.json +++ b/avm/res/network/dns-zone/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "15615003934018920895" + "templateHash": "8227493623153563126" }, "name": "Public DNS Zones", "description": "This module deploys a Public DNS zone.", @@ -46,7 +46,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -194,7 +194,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -288,7 +288,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -344,7 +344,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "5102357917037426899" + "templateHash": "12120328600933901484" }, "name": "Public DNS Zone A record", "description": "This module deploys a Public DNS Zone A record.", @@ -359,7 +359,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -462,7 +462,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -512,7 +512,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/A/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/A', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -598,7 +598,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "15377155277897248268" + "templateHash": "1358707556106672388" }, "name": "Public DNS Zone AAAA record", "description": "This module deploys a Public DNS Zone AAAA record.", @@ -613,7 +613,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -716,7 +716,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -766,7 +766,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/AAAA/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/AAAA', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -852,7 +852,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "15202379687273336739" + "templateHash": "2252647874269685796" }, "name": "Public DNS Zone CNAME record", "description": "This module deploys a Public DNS Zone CNAME record.", @@ -867,7 +867,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -970,7 +970,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -1020,7 +1020,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/CNAME/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/CNAME', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -1103,7 +1103,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "14137420953130091892" + "templateHash": "13353997192315697593" }, "name": "Public DNS Zone CAA record", "description": "This module deploys a Public DNS Zone CAA record.", @@ -1118,7 +1118,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -1214,7 +1214,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -1263,7 +1263,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/CAA/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/CAA', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -1346,7 +1346,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "7290500674933661124" + "templateHash": "5038605698705304271" }, "name": "Public DNS Zone MX record", "description": "This module deploys a Public DNS Zone MX record.", @@ -1361,7 +1361,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -1457,7 +1457,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -1506,7 +1506,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/MX/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/MX', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -1589,7 +1589,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "1612913715306979831" + "templateHash": "3485709467033128611" }, "name": "Public DNS Zone NS record", "description": "This module deploys a Public DNS Zone NS record.", @@ -1604,7 +1604,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -1700,7 +1700,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -1749,7 +1749,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/NS/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/NS', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -1832,7 +1832,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "18439161764270488124" + "templateHash": "5404924153419525957" }, "name": "Public DNS Zone PTR record", "description": "This module deploys a Public DNS Zone PTR record.", @@ -1847,7 +1847,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -1943,7 +1943,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -1992,7 +1992,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/PTR/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/PTR', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -2075,7 +2075,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "6819223668967518740" + "templateHash": "556736268928776505" }, "name": "Public DNS Zone SOA record", "description": "This module deploys a Public DNS Zone SOA record.", @@ -2090,7 +2090,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -2186,7 +2186,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -2235,7 +2235,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/SOA/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/SOA', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -2318,7 +2318,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "534263969679389743" + "templateHash": "14676874604766286912" }, "name": "Public DNS Zone SRV record", "description": "This module deploys a Public DNS Zone SRV record.", @@ -2333,7 +2333,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -2429,7 +2429,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -2478,7 +2478,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/SRV/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/SRV', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -2561,7 +2561,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "8365521613212782334" + "templateHash": "2944918250308832972" }, "name": "Public DNS Zone TXT record", "description": "This module deploys a Public DNS Zone TXT record.", @@ -2576,7 +2576,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -2672,7 +2672,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -2721,7 +2721,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/TXT/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/TXT', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/dns-zone/mx/README.md b/avm/res/network/dns-zone/mx/README.md index 8ce9945792..ecea7d5b30 100644 --- a/avm/res/network/dns-zone/mx/README.md +++ b/avm/res/network/dns-zone/mx/README.md @@ -36,7 +36,7 @@ This module deploys a Public DNS Zone MX record. | :-- | :-- | :-- | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | | [`mxRecords`](#parameter-mxrecords) | array | The list of MX records in the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | ### Parameter: `dnsZoneName` @@ -65,7 +65,7 @@ The name of the MX record. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -78,7 +78,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -126,7 +126,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/dns-zone/mx/main.bicep b/avm/res/network/dns-zone/mx/main.bicep index a6e1e6fe13..d6698e40b8 100644 --- a/avm/res/network/dns-zone/mx/main.bicep +++ b/avm/res/network/dns-zone/mx/main.bicep @@ -17,7 +17,7 @@ param mxRecords array? @description('Optional. The TTL (time-to-live) of the records in the record set.') param ttl int = 3600 -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -51,7 +51,7 @@ resource MX 'Microsoft.Network/dnsZones/MX@2018-05-01' = { resource MX_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(MX.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -75,7 +75,7 @@ output resourceGroupName string = resourceGroup().name // =============== // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/dns-zone/mx/main.json b/avm/res/network/dns-zone/mx/main.json index 8025b838e3..7b20c90b39 100644 --- a/avm/res/network/dns-zone/mx/main.json +++ b/avm/res/network/dns-zone/mx/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "7290500674933661124" + "templateHash": "5038605698705304271" }, "name": "Public DNS Zone MX record", "description": "This module deploys a Public DNS Zone MX record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -117,7 +117,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -166,7 +166,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/MX/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/MX', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/dns-zone/ns/README.md b/avm/res/network/dns-zone/ns/README.md index 29587268bd..87744ff0e9 100644 --- a/avm/res/network/dns-zone/ns/README.md +++ b/avm/res/network/dns-zone/ns/README.md @@ -36,7 +36,7 @@ This module deploys a Public DNS Zone NS record. | :-- | :-- | :-- | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | | [`nsRecords`](#parameter-nsrecords) | array | The list of NS records in the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | ### Parameter: `dnsZoneName` @@ -65,7 +65,7 @@ The list of NS records in the record set. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -78,7 +78,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -126,7 +126,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/dns-zone/ns/main.bicep b/avm/res/network/dns-zone/ns/main.bicep index bae95154d0..77822daf5c 100644 --- a/avm/res/network/dns-zone/ns/main.bicep +++ b/avm/res/network/dns-zone/ns/main.bicep @@ -17,7 +17,7 @@ param nsRecords array? @description('Optional. The TTL (time-to-live) of the records in the record set.') param ttl int = 3600 -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -50,7 +50,7 @@ resource NS 'Microsoft.Network/dnsZones/NS@2018-05-01' = { resource NS_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(NS.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -74,7 +74,7 @@ output resourceGroupName string = resourceGroup().name // =============== // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/dns-zone/ns/main.json b/avm/res/network/dns-zone/ns/main.json index 632f9a6ada..56b77f2814 100644 --- a/avm/res/network/dns-zone/ns/main.json +++ b/avm/res/network/dns-zone/ns/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "1612913715306979831" + "templateHash": "3485709467033128611" }, "name": "Public DNS Zone NS record", "description": "This module deploys a Public DNS Zone NS record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -117,7 +117,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -166,7 +166,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/NS/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/NS', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/dns-zone/ptr/README.md b/avm/res/network/dns-zone/ptr/README.md index d79837edc9..5395cc64b2 100644 --- a/avm/res/network/dns-zone/ptr/README.md +++ b/avm/res/network/dns-zone/ptr/README.md @@ -36,7 +36,7 @@ This module deploys a Public DNS Zone PTR record. | :-- | :-- | :-- | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | | [`ptrRecords`](#parameter-ptrrecords) | array | The list of PTR records in the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | ### Parameter: `dnsZoneName` @@ -65,7 +65,7 @@ The list of PTR records in the record set. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -78,7 +78,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -126,7 +126,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/dns-zone/ptr/main.bicep b/avm/res/network/dns-zone/ptr/main.bicep index 9c8b10bfe1..88ae334fb1 100644 --- a/avm/res/network/dns-zone/ptr/main.bicep +++ b/avm/res/network/dns-zone/ptr/main.bicep @@ -17,7 +17,7 @@ param ptrRecords array? @description('Optional. The TTL (time-to-live) of the records in the record set.') param ttl int = 3600 -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -51,7 +51,7 @@ resource PTR 'Microsoft.Network/dnsZones/PTR@2018-05-01' = { resource PTR_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(PTR.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -75,7 +75,7 @@ output resourceGroupName string = resourceGroup().name // =============== // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/dns-zone/ptr/main.json b/avm/res/network/dns-zone/ptr/main.json index 03505a6b39..8474844564 100644 --- a/avm/res/network/dns-zone/ptr/main.json +++ b/avm/res/network/dns-zone/ptr/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "18439161764270488124" + "templateHash": "5404924153419525957" }, "name": "Public DNS Zone PTR record", "description": "This module deploys a Public DNS Zone PTR record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -117,7 +117,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -166,7 +166,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/PTR/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/PTR', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/dns-zone/soa/README.md b/avm/res/network/dns-zone/soa/README.md index 47a53432b7..a987a8eaec 100644 --- a/avm/res/network/dns-zone/soa/README.md +++ b/avm/res/network/dns-zone/soa/README.md @@ -35,7 +35,7 @@ This module deploys a Public DNS Zone SOA record. | Parameter | Type | Description | | :-- | :-- | :-- | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`soaRecord`](#parameter-soarecord) | object | A SOA record. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | @@ -59,7 +59,7 @@ The name of the SOA record. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -72,7 +72,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -120,7 +120,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/dns-zone/soa/main.bicep b/avm/res/network/dns-zone/soa/main.bicep index 4aeacac21a..84985f7995 100644 --- a/avm/res/network/dns-zone/soa/main.bicep +++ b/avm/res/network/dns-zone/soa/main.bicep @@ -17,7 +17,7 @@ param soaRecord object? @description('Optional. The TTL (time-to-live) of the records in the record set.') param ttl int = 3600 -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -51,7 +51,7 @@ resource SOA 'Microsoft.Network/dnsZones/SOA@2018-05-01' = { resource SOA_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(SOA.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -75,7 +75,7 @@ output resourceGroupName string = resourceGroup().name // =============== // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/dns-zone/soa/main.json b/avm/res/network/dns-zone/soa/main.json index 90253daac5..0e1047ca87 100644 --- a/avm/res/network/dns-zone/soa/main.json +++ b/avm/res/network/dns-zone/soa/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "6819223668967518740" + "templateHash": "556736268928776505" }, "name": "Public DNS Zone SOA record", "description": "This module deploys a Public DNS Zone SOA record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -117,7 +117,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -166,7 +166,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/SOA/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/SOA', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/dns-zone/srv/README.md b/avm/res/network/dns-zone/srv/README.md index 12e475068b..3e219c0411 100644 --- a/avm/res/network/dns-zone/srv/README.md +++ b/avm/res/network/dns-zone/srv/README.md @@ -35,7 +35,7 @@ This module deploys a Public DNS Zone SRV record. | Parameter | Type | Description | | :-- | :-- | :-- | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`srvRecords`](#parameter-srvrecords) | array | The list of SRV records in the record set. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | @@ -59,7 +59,7 @@ The name of the SRV record. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -72,7 +72,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -120,7 +120,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/dns-zone/srv/main.bicep b/avm/res/network/dns-zone/srv/main.bicep index 30894ef208..3a1bff756d 100644 --- a/avm/res/network/dns-zone/srv/main.bicep +++ b/avm/res/network/dns-zone/srv/main.bicep @@ -17,7 +17,7 @@ param srvRecords array? @description('Optional. The TTL (time-to-live) of the records in the record set.') param ttl int = 3600 -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -50,7 +50,7 @@ resource SRV 'Microsoft.Network/dnsZones/SRV@2018-05-01' = { resource SRV_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(SRV.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -74,7 +74,7 @@ output resourceGroupName string = resourceGroup().name // =============== // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/dns-zone/srv/main.json b/avm/res/network/dns-zone/srv/main.json index bfd298a34a..203529295a 100644 --- a/avm/res/network/dns-zone/srv/main.json +++ b/avm/res/network/dns-zone/srv/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "534263969679389743" + "templateHash": "14676874604766286912" }, "name": "Public DNS Zone SRV record", "description": "This module deploys a Public DNS Zone SRV record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -117,7 +117,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -166,7 +166,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/SRV/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/SRV', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/dns-zone/tests/e2e/defaults/main.test.bicep b/avm/res/network/dns-zone/tests/e2e/defaults/main.test.bicep index 4824356459..51671d7ce1 100644 --- a/avm/res/network/dns-zone/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/dns-zone/tests/e2e/defaults/main.test.bicep @@ -42,19 +42,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' params: { name: '${namePrefix}${serviceShort}001.com' location: 'global' - // Workaround for PSRule - a: [] - aaaa: [] - cname: [] - mx: [] - ptr: [] - soa: [] - srv: [] - txt: [] - lock: {} - roleAssignments: [] - caa: [] - ns: [] - tags: {} } }] diff --git a/avm/res/network/dns-zone/tests/e2e/max/main.test.bicep b/avm/res/network/dns-zone/tests/e2e/max/main.test.bicep index a454c4834f..25588e8228 100644 --- a/avm/res/network/dns-zone/tests/e2e/max/main.test.bicep +++ b/avm/res/network/dns-zone/tests/e2e/max/main.test.bicep @@ -62,7 +62,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: 'A_10.240.4.4' roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -89,7 +99,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: 'CNAME_test' roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -116,7 +136,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: 'MX_contoso' roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -134,7 +164,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -144,7 +184,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -154,7 +204,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: '@' roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -176,7 +236,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: 'SRV_contoso' roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -197,7 +267,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: 'TXT_test' roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/network/dns-zone/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/dns-zone/tests/e2e/waf-aligned/main.test.bicep index d9ff9ef047..9a0dd49254 100644 --- a/avm/res/network/dns-zone/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/dns-zone/tests/e2e/waf-aligned/main.test.bicep @@ -52,19 +52,10 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' params: { name: '${namePrefix}${serviceShort}001.com' location: 'global' - a: [] - aaaa: [] - cname: [] lock: { kind: 'CanNotDelete' name: 'myCustomLockName' } - mx: [] - ptr: [] - roleAssignments: [] - soa: [] - srv: [] - txt: [] tags: { 'hidden-title': 'This is visible in the resource name' Environment: 'Non-Prod' diff --git a/avm/res/network/dns-zone/txt/README.md b/avm/res/network/dns-zone/txt/README.md index f8c8867ab4..1bccdf1324 100644 --- a/avm/res/network/dns-zone/txt/README.md +++ b/avm/res/network/dns-zone/txt/README.md @@ -35,7 +35,7 @@ This module deploys a Public DNS Zone TXT record. | Parameter | Type | Description | | :-- | :-- | :-- | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | | [`txtRecords`](#parameter-txtrecords) | array | The list of TXT records in the record set. | @@ -59,7 +59,7 @@ The name of the TXT record. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -72,7 +72,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -120,7 +120,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/dns-zone/txt/main.bicep b/avm/res/network/dns-zone/txt/main.bicep index 382f99677f..b363e23cf0 100644 --- a/avm/res/network/dns-zone/txt/main.bicep +++ b/avm/res/network/dns-zone/txt/main.bicep @@ -17,7 +17,7 @@ param ttl int = 3600 @description('Optional. The list of TXT records in the record set.') param txtRecords 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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -50,7 +50,7 @@ resource TXT 'Microsoft.Network/dnsZones/TXT@2018-05-01' = { resource TXT_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(TXT.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -74,7 +74,7 @@ output resourceGroupName string = resourceGroup().name // =============== // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/dns-zone/txt/main.json b/avm/res/network/dns-zone/txt/main.json index 7343be271e..8f9336f724 100644 --- a/avm/res/network/dns-zone/txt/main.json +++ b/avm/res/network/dns-zone/txt/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "8365521613212782334" + "templateHash": "2944918250308832972" }, "name": "Public DNS Zone TXT record", "description": "This module deploys a Public DNS Zone TXT record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -117,7 +117,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -166,7 +166,7 @@ "scope": "[format('Microsoft.Network/dnsZones/{0}/TXT/{1}', parameters('dnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/dnsZones/TXT', parameters('dnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/express-route-circuit/README.md b/avm/res/network/express-route-circuit/README.md index dcb88c2a2f..8296a46e01 100644 --- a/avm/res/network/express-route-circuit/README.md +++ b/avm/res/network/express-route-circuit/README.md @@ -134,7 +134,17 @@ module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit:' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] skuFamily: 'MeteredData' @@ -145,7 +155,7 @@ module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit:", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, diff --git a/avm/res/network/express-route-circuit/main.bicep b/avm/res/network/express-route-circuit/main.bicep index 9f880c3798..87662d3425 100644 --- a/avm/res/network/express-route-circuit/main.bicep +++ b/avm/res/network/express-route-circuit/main.bicep @@ -85,7 +85,6 @@ param tags object? @description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') param enableTelemetry bool = true - var builtInRoleNames = { Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') 'Network Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7') @@ -188,7 +187,7 @@ resource expressRouteCircuits_diagnosticSettings 'Microsoft.Insights/diagnosticS resource expressRouteCircuits_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(expressRouteCircuits.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType diff --git a/avm/res/network/express-route-circuit/main.json b/avm/res/network/express-route-circuit/main.json index 99287afe22..aa9ed2cc25 100644 --- a/avm/res/network/express-route-circuit/main.json +++ b/avm/res/network/express-route-circuit/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "9887015317023929385" + "templateHash": "16272530552137395149" }, "name": "ExpressRoute Circuits", "description": "This module deploys an Express Route Circuit.", @@ -482,7 +482,7 @@ "scope": "[format('Microsoft.Network/expressRouteCircuits/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/expressRouteCircuits', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/express-route-circuit/tests/e2e/max/main.test.bicep b/avm/res/network/express-route-circuit/tests/e2e/max/main.test.bicep index ec8bdc5151..fcbde41067 100644 --- a/avm/res/network/express-route-circuit/tests/e2e/max/main.test.bicep +++ b/avm/res/network/express-route-circuit/tests/e2e/max/main.test.bicep @@ -87,7 +87,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' } roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -101,7 +111,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } - dependsOn: [nestedDependencies] + dependsOn: [ nestedDependencies ] }] - - diff --git a/avm/res/network/express-route-gateway/README.md b/avm/res/network/express-route-gateway/README.md index 8de1fbc892..336e318a0b 100644 --- a/avm/res/network/express-route-gateway/README.md +++ b/avm/res/network/express-route-gateway/README.md @@ -115,7 +115,17 @@ module expressRouteGateway 'br/public:avm/res/network/express-route-gateway:' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] tags: { @@ -169,7 +179,17 @@ module expressRouteGateway 'br/public:avm/res/network/express-route-gateway:", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -291,7 +311,7 @@ module expressRouteGateway 'br/public:avm/res/network/express-route-gateway:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] skuName: 'Standard' @@ -282,7 +292,17 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -422,7 +442,17 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] tags: { @@ -573,7 +603,17 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -710,7 +750,17 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] tags: { @@ -861,7 +911,17 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -902,7 +962,7 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = { | [`lock`](#parameter-lock) | object | The lock settings of the service. | | [`outboundRules`](#parameter-outboundrules) | array | The outbound rules. | | [`probes`](#parameter-probes) | array | Array of objects containing all probes, these are references in the load balancing rules. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`skuName`](#parameter-skuname) | string | Name of a load balancer SKU. | | [`tags`](#parameter-tags) | object | Tags of the resource. | @@ -1080,7 +1140,7 @@ Array of objects containing all probes, these are references in the load balanci ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -1093,7 +1153,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -1141,7 +1201,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/load-balancer/main.bicep b/avm/res/network/load-balancer/main.bicep index a1fba73b39..e85f055835 100644 --- a/avm/res/network/load-balancer/main.bicep +++ b/avm/res/network/load-balancer/main.bicep @@ -38,7 +38,7 @@ param diagnosticSettings diagnosticSettingType @description('Optional. The lock settings of the service.') param lock lockType -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. Tags of the resource.') @@ -245,7 +245,7 @@ resource loadBalancer_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@ resource loadBalancer_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(loadBalancer.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -317,7 +317,7 @@ type lockType = { }? type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/load-balancer/main.json b/avm/res/network/load-balancer/main.json index 3550a4e64f..bc62b1c336 100644 --- a/avm/res/network/load-balancer/main.json +++ b/avm/res/network/load-balancer/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "1520201606839870909" + "templateHash": "179000411358609198" }, "name": "Load Balancers", "description": "This module deploys a Load Balancer.", @@ -126,7 +126,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -253,7 +253,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -465,7 +465,7 @@ "scope": "[format('Microsoft.Network/loadBalancers/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/loadBalancers', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/load-balancer/tests/e2e/internal/main.test.bicep b/avm/res/network/load-balancer/tests/e2e/internal/main.test.bicep index 291f24a444..72a0a57bb5 100644 --- a/avm/res/network/load-balancer/tests/e2e/internal/main.test.bicep +++ b/avm/res/network/load-balancer/tests/e2e/internal/main.test.bicep @@ -109,7 +109,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/network/load-balancer/tests/e2e/max/main.test.bicep b/avm/res/network/load-balancer/tests/e2e/max/main.test.bicep index 6d2a068fea..f05076a241 100644 --- a/avm/res/network/load-balancer/tests/e2e/max/main.test.bicep +++ b/avm/res/network/load-balancer/tests/e2e/max/main.test.bicep @@ -166,7 +166,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/network/load-balancer/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/load-balancer/tests/e2e/waf-aligned/main.test.bicep index 69b43753ad..33786dff9c 100644 --- a/avm/res/network/load-balancer/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/load-balancer/tests/e2e/waf-aligned/main.test.bicep @@ -166,7 +166,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/network/network-interface/README.md b/avm/res/network/network-interface/README.md index 54ca2bf43a..e7802fb13b 100644 --- a/avm/res/network/network-interface/README.md +++ b/avm/res/network/network-interface/README.md @@ -53,11 +53,7 @@ module networkInterface 'br/public:avm/res/network/network-interface:' ] name: 'nnimin001' // Non-required parameters - diagnosticSettings: '' location: '' - lock: '' - roleAssignments: '' - tags: {} } } ``` @@ -87,20 +83,8 @@ module networkInterface 'br/public:avm/res/network/network-interface:' "value": "nnimin001" }, // Non-required parameters - "diagnosticSettings": { - "value": "" - }, "location": { "value": "" - }, - "lock": { - "value": "" - }, - "roleAssignments": { - "value": "" - }, - "tags": { - "value": {} } } } @@ -167,7 +151,17 @@ module networkInterface 'br/public:avm/res/network/network-interface:' { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] tags: { @@ -247,7 +241,17 @@ module networkInterface 'br/public:avm/res/network/network-interface:' { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -420,7 +424,7 @@ module networkInterface 'br/public:avm/res/network/network-interface:' | [`location`](#parameter-location) | string | Location for all resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | | [`networkSecurityGroupResourceId`](#parameter-networksecuritygroupresourceid) | string | The network security group (NSG) to attach to the network interface. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`tags`](#parameter-tags) | object | Resource tags. | ### Parameter: `auxiliaryMode` @@ -660,7 +664,7 @@ The network security group (NSG) to attach to the network interface. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -673,7 +677,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -721,7 +725,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/network-interface/main.bicep b/avm/res/network/network-interface/main.bicep index aafd5000a2..b8a1a36788 100644 --- a/avm/res/network/network-interface/main.bicep +++ b/avm/res/network/network-interface/main.bicep @@ -53,7 +53,7 @@ param ipConfigurations array @description('Optional. The lock settings of the service.') param lock lockType -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. The diagnostic settings of the service.') @@ -164,7 +164,7 @@ resource networkInterface_diagnosticSettings 'Microsoft.Insights/diagnosticSetti resource networkInterface_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(networkInterface.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -233,7 +233,7 @@ type diagnosticSettingType = { }[]? type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/network-interface/main.json b/avm/res/network/network-interface/main.json index 230c137ee1..d8b7518397 100644 --- a/avm/res/network/network-interface/main.json +++ b/avm/res/network/network-interface/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "13839054472745469471" + "templateHash": "14617314094453038306" }, "name": "Network Interface", "description": "This module deploys a Network Interface.", @@ -127,7 +127,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -315,7 +315,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "diagnosticSettings": { @@ -445,7 +445,7 @@ "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/network-interface/tests/e2e/defaults/main.test.bicep b/avm/res/network/network-interface/tests/e2e/defaults/main.test.bicep index dac7d45d5b..8c81d40c45 100644 --- a/avm/res/network/network-interface/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/network-interface/tests/e2e/defaults/main.test.bicep @@ -57,10 +57,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' subnetResourceId: nestedDependencies.outputs.subnetResourceId } ] - // Workaround for PSRule - lock: null - diagnosticSettings: null - roleAssignments: null - tags: {} } }] diff --git a/avm/res/network/network-interface/tests/e2e/max/main.test.bicep b/avm/res/network/network-interface/tests/e2e/max/main.test.bicep index c987f6cf95..f4e2963622 100644 --- a/avm/res/network/network-interface/tests/e2e/max/main.test.bicep +++ b/avm/res/network/network-interface/tests/e2e/max/main.test.bicep @@ -107,7 +107,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' } roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/network/private-dns-zone/README.md b/avm/res/network/private-dns-zone/README.md index cf3569bc25..43adc1e6db 100644 --- a/avm/res/network/private-dns-zone/README.md +++ b/avm/res/network/private-dns-zone/README.md @@ -57,18 +57,7 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { // Required parameters name: 'npdzmin001.com' // Non-required parameters - a: [] - aaaa: [] - cname: [] location: 'global' - lock: {} - mx: [] - ptr: [] - roleAssignments: [] - soa: [] - srv: [] - txt: [] - virtualNetworkLinks: [] } } ``` @@ -90,41 +79,8 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { "value": "npdzmin001.com" }, // Non-required parameters - "a": { - "value": [] - }, - "aaaa": { - "value": [] - }, - "cname": { - "value": [] - }, "location": { "value": "global" - }, - "lock": { - "value": {} - }, - "mx": { - "value": [] - }, - "ptr": { - "value": [] - }, - "roleAssignments": { - "value": [] - }, - "soa": { - "value": [] - }, - "srv": { - "value": [] - }, - "txt": { - "value": [] - }, - "virtualNetworkLinks": { - "value": [] } } } @@ -161,7 +117,17 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] ttl: 3600 @@ -188,7 +154,17 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] ttl: 3600 @@ -212,7 +188,17 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] ttl: 3600 @@ -230,7 +216,17 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] ttl: 3600 @@ -240,7 +236,17 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] soa: [ @@ -250,7 +256,17 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] soaRecord: { @@ -272,7 +288,17 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] srvRecords: [ @@ -298,7 +324,17 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] ttl: 3600 @@ -351,7 +387,17 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "ttl": 3600 @@ -382,7 +428,17 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "ttl": 3600 @@ -412,7 +468,17 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "ttl": 3600 @@ -432,7 +498,17 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "ttl": 3600 @@ -444,7 +520,17 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -456,7 +542,17 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "soaRecord": { @@ -480,7 +576,17 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "srvRecords": [ @@ -510,7 +616,17 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ], "ttl": 3600, @@ -555,25 +671,16 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { // Required parameters name: 'npdzwaf001.com' // Non-required parameters - a: [] - aaaa: [] - cname: [] location: 'global' lock: { kind: 'CanNotDelete' name: 'myCustomLockName' } - mx: [] - ptr: [] - roleAssignments: [] - soa: [] - srv: [] tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - txt: [] } } ``` @@ -595,15 +702,6 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { "value": "npdzwaf001.com" }, // Non-required parameters - "a": { - "value": [] - }, - "aaaa": { - "value": [] - }, - "cname": { - "value": [] - }, "location": { "value": "global" }, @@ -613,30 +711,12 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { "name": "myCustomLockName" } }, - "mx": { - "value": [] - }, - "ptr": { - "value": [] - }, - "roleAssignments": { - "value": [] - }, - "soa": { - "value": [] - }, - "srv": { - "value": [] - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "txt": { - "value": [] } } } @@ -666,7 +746,7 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { | [`lock`](#parameter-lock) | object | The lock settings of the service. | | [`mx`](#parameter-mx) | array | Array of MX records. | | [`ptr`](#parameter-ptr) | array | Array of PTR records. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`soa`](#parameter-soa) | array | Array of SOA records. | | [`srv`](#parameter-srv) | array | Array of SRV records. | | [`tags`](#parameter-tags) | object | Tags of the resource. | @@ -752,7 +832,7 @@ Array of PTR records. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -765,7 +845,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -813,7 +893,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/private-dns-zone/a/README.md b/avm/res/network/private-dns-zone/a/README.md index c9e01cd868..1b7665fe7d 100644 --- a/avm/res/network/private-dns-zone/a/README.md +++ b/avm/res/network/private-dns-zone/a/README.md @@ -36,7 +36,7 @@ This module deploys a Private DNS Zone A record. | :-- | :-- | :-- | | [`aRecords`](#parameter-arecords) | array | The list of A records in the record set. | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | ### Parameter: `aRecords` @@ -65,7 +65,7 @@ The name of the parent Private DNS zone. Required if the template is used in a s ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -78,7 +78,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -126,7 +126,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/private-dns-zone/a/main.bicep b/avm/res/network/private-dns-zone/a/main.bicep index dd8179828f..b4a4e1776e 100644 --- a/avm/res/network/private-dns-zone/a/main.bicep +++ b/avm/res/network/private-dns-zone/a/main.bicep @@ -17,7 +17,7 @@ param metadata object? @description('Optional. The TTL (time-to-live) of the records in the record set.') param ttl int = 3600 -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -47,7 +47,7 @@ resource A 'Microsoft.Network/privateDnsZones/A@2020-06-01' = { resource A_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(A.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -72,7 +72,7 @@ output resourceGroupName string = resourceGroup().name // ================ // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/private-dns-zone/a/main.json b/avm/res/network/private-dns-zone/a/main.json index e72a4acb2c..8818c33ba6 100644 --- a/avm/res/network/private-dns-zone/a/main.json +++ b/avm/res/network/private-dns-zone/a/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "3178897665223689126" + "templateHash": "11167365460932069899" }, "name": "Private DNS Zone A record", "description": "This module deploys a Private DNS Zone A record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -117,7 +117,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -162,7 +162,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}/A/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/private-dns-zone/aaaa/README.md b/avm/res/network/private-dns-zone/aaaa/README.md index 71518495b1..c1e1c34ff2 100644 --- a/avm/res/network/private-dns-zone/aaaa/README.md +++ b/avm/res/network/private-dns-zone/aaaa/README.md @@ -36,7 +36,7 @@ This module deploys a Private DNS Zone AAAA record. | :-- | :-- | :-- | | [`aaaaRecords`](#parameter-aaaarecords) | array | The list of AAAA records in the record set. | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | ### Parameter: `aaaaRecords` @@ -65,7 +65,7 @@ The name of the parent Private DNS zone. Required if the template is used in a s ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -78,7 +78,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -126,7 +126,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/private-dns-zone/aaaa/main.bicep b/avm/res/network/private-dns-zone/aaaa/main.bicep index a280069afb..861dcfe50f 100644 --- a/avm/res/network/private-dns-zone/aaaa/main.bicep +++ b/avm/res/network/private-dns-zone/aaaa/main.bicep @@ -17,7 +17,7 @@ param metadata object? @description('Optional. The TTL (time-to-live) of the records in the record set.') param ttl int = 3600 -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -47,7 +47,7 @@ resource AAAA 'Microsoft.Network/privateDnsZones/AAAA@2020-06-01' = { resource AAAA_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(AAAA.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -72,7 +72,7 @@ output resourceGroupName string = resourceGroup().name // ================ // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/private-dns-zone/aaaa/main.json b/avm/res/network/private-dns-zone/aaaa/main.json index ba3df83041..c28d30ee63 100644 --- a/avm/res/network/private-dns-zone/aaaa/main.json +++ b/avm/res/network/private-dns-zone/aaaa/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "13336554047293852625" + "templateHash": "8477739334940944892" }, "name": "Private DNS Zone AAAA record", "description": "This module deploys a Private DNS Zone AAAA record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -117,7 +117,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -162,7 +162,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}/AAAA/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/private-dns-zone/cname/README.md b/avm/res/network/private-dns-zone/cname/README.md index de536f01bf..3e839822c0 100644 --- a/avm/res/network/private-dns-zone/cname/README.md +++ b/avm/res/network/private-dns-zone/cname/README.md @@ -36,7 +36,7 @@ This module deploys a Private DNS Zone CNAME record. | :-- | :-- | :-- | | [`cnameRecord`](#parameter-cnamerecord) | object | A CNAME record. | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | ### Parameter: `cnameRecord` @@ -66,7 +66,7 @@ The name of the parent Private DNS zone. Required if the template is used in a s ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -79,7 +79,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -127,7 +127,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/private-dns-zone/cname/main.bicep b/avm/res/network/private-dns-zone/cname/main.bicep index bdc34c9128..3d38a355a5 100644 --- a/avm/res/network/private-dns-zone/cname/main.bicep +++ b/avm/res/network/private-dns-zone/cname/main.bicep @@ -17,7 +17,7 @@ param metadata object? @description('Optional. The TTL (time-to-live) of the records in the record set.') param ttl int = 3600 -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -47,7 +47,7 @@ resource CNAME 'Microsoft.Network/privateDnsZones/CNAME@2020-06-01' = { resource CNAME_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(CNAME.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -72,7 +72,7 @@ output resourceGroupName string = resourceGroup().name // ================ // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/private-dns-zone/cname/main.json b/avm/res/network/private-dns-zone/cname/main.json index 0627ed35cc..beb4c3a77d 100644 --- a/avm/res/network/private-dns-zone/cname/main.json +++ b/avm/res/network/private-dns-zone/cname/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "15225042375721382797" + "templateHash": "1824251508069141831" }, "name": "Private DNS Zone CNAME record", "description": "This module deploys a Private DNS Zone CNAME record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -117,7 +117,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -162,7 +162,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}/CNAME/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/private-dns-zone/main.bicep b/avm/res/network/private-dns-zone/main.bicep index 87e54bb8c8..ab697333d1 100644 --- a/avm/res/network/private-dns-zone/main.bicep +++ b/avm/res/network/private-dns-zone/main.bicep @@ -35,7 +35,7 @@ param virtualNetworkLinks array? @description('Optional. The location of the PrivateDNSZone. Should be global.') param location string = 'global' -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. Tags of the resource.') @@ -200,7 +200,7 @@ resource privateDnsZone_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!e resource privateDnsZone_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(privateDnsZone.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -228,7 +228,7 @@ output location string = privateDnsZone.location // ================ // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/private-dns-zone/main.json b/avm/res/network/private-dns-zone/main.json index a45a1fe38f..1650f9443e 100644 --- a/avm/res/network/private-dns-zone/main.json +++ b/avm/res/network/private-dns-zone/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "17577658862428842934" + "templateHash": "14993372533742094161" }, "name": "Private DNS Zones", "description": "This module deploys a Private DNS zone.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -185,7 +185,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -271,7 +271,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -324,7 +324,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "3178897665223689126" + "templateHash": "11167365460932069899" }, "name": "Private DNS Zone A record", "description": "This module deploys a Private DNS Zone A record.", @@ -339,7 +339,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -435,7 +435,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -480,7 +480,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}/A/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -563,7 +563,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "13336554047293852625" + "templateHash": "8477739334940944892" }, "name": "Private DNS Zone AAAA record", "description": "This module deploys a Private DNS Zone AAAA record.", @@ -578,7 +578,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -674,7 +674,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -719,7 +719,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}/AAAA/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -802,7 +802,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "15225042375721382797" + "templateHash": "1824251508069141831" }, "name": "Private DNS Zone CNAME record", "description": "This module deploys a Private DNS Zone CNAME record.", @@ -817,7 +817,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -913,7 +913,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -958,7 +958,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}/CNAME/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -1041,7 +1041,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "15979724882776547112" + "templateHash": "16766647288374726215" }, "name": "Private DNS Zone MX record", "description": "This module deploys a Private DNS Zone MX record.", @@ -1056,7 +1056,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -1152,7 +1152,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -1197,7 +1197,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}/MX/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -1280,7 +1280,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "13360561055754827389" + "templateHash": "4240560893124737328" }, "name": "Private DNS Zone PTR record", "description": "This module deploys a Private DNS Zone PTR record.", @@ -1295,7 +1295,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -1391,7 +1391,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -1436,7 +1436,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}/PTR/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -1519,7 +1519,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "2022546465907048440" + "templateHash": "16534327059574132227" }, "name": "Private DNS Zone SOA record", "description": "This module deploys a Private DNS Zone SOA record.", @@ -1534,7 +1534,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -1630,7 +1630,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -1675,7 +1675,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}/SOA/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -1758,7 +1758,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "11017781799470369462" + "templateHash": "10336254327206850957" }, "name": "Private DNS Zone SRV record", "description": "This module deploys a Private DNS Zone SRV record.", @@ -1773,7 +1773,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -1869,7 +1869,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -1914,7 +1914,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}/SRV/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -1997,7 +1997,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "13485919432065481500" + "templateHash": "14853546982840308619" }, "name": "Private DNS Zone TXT record", "description": "This module deploys a Private DNS Zone TXT record.", @@ -2012,7 +2012,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -2108,7 +2108,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -2153,7 +2153,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}/TXT/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/private-dns-zone/mx/README.md b/avm/res/network/private-dns-zone/mx/README.md index c91447886f..7a8c8ff406 100644 --- a/avm/res/network/private-dns-zone/mx/README.md +++ b/avm/res/network/private-dns-zone/mx/README.md @@ -36,7 +36,7 @@ This module deploys a Private DNS Zone MX record. | :-- | :-- | :-- | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | | [`mxRecords`](#parameter-mxrecords) | array | The list of MX records in the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | ### Parameter: `metadata` @@ -65,7 +65,7 @@ The name of the parent Private DNS zone. Required if the template is used in a s ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -78,7 +78,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -126,7 +126,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/private-dns-zone/mx/main.bicep b/avm/res/network/private-dns-zone/mx/main.bicep index e404b598e1..d3f7b50c27 100644 --- a/avm/res/network/private-dns-zone/mx/main.bicep +++ b/avm/res/network/private-dns-zone/mx/main.bicep @@ -17,7 +17,7 @@ param mxRecords array? @description('Optional. The TTL (time-to-live) of the records in the record set.') param ttl int = 3600 -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -47,7 +47,7 @@ resource MX 'Microsoft.Network/privateDnsZones/MX@2020-06-01' = { resource MX_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(MX.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -72,7 +72,7 @@ output resourceGroupName string = resourceGroup().name // ================ // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/private-dns-zone/mx/main.json b/avm/res/network/private-dns-zone/mx/main.json index c0d2834439..647ccd2037 100644 --- a/avm/res/network/private-dns-zone/mx/main.json +++ b/avm/res/network/private-dns-zone/mx/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "15979724882776547112" + "templateHash": "16766647288374726215" }, "name": "Private DNS Zone MX record", "description": "This module deploys a Private DNS Zone MX record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -117,7 +117,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -162,7 +162,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}/MX/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/private-dns-zone/ptr/README.md b/avm/res/network/private-dns-zone/ptr/README.md index 46b887ecd0..0a8e736fc7 100644 --- a/avm/res/network/private-dns-zone/ptr/README.md +++ b/avm/res/network/private-dns-zone/ptr/README.md @@ -36,7 +36,7 @@ This module deploys a Private DNS Zone PTR record. | :-- | :-- | :-- | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | | [`ptrRecords`](#parameter-ptrrecords) | array | The list of PTR records in the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | ### Parameter: `metadata` @@ -65,7 +65,7 @@ The list of PTR records in the record set. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -78,7 +78,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -126,7 +126,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/private-dns-zone/ptr/main.bicep b/avm/res/network/private-dns-zone/ptr/main.bicep index 8caeb1c47e..c90dc4afbb 100644 --- a/avm/res/network/private-dns-zone/ptr/main.bicep +++ b/avm/res/network/private-dns-zone/ptr/main.bicep @@ -17,7 +17,7 @@ param ptrRecords array? @description('Optional. The TTL (time-to-live) of the records in the record set.') param ttl int = 3600 -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -47,7 +47,7 @@ resource PTR 'Microsoft.Network/privateDnsZones/PTR@2020-06-01' = { resource PTR_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(PTR.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -72,7 +72,7 @@ output resourceGroupName string = resourceGroup().name // ================ // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/private-dns-zone/ptr/main.json b/avm/res/network/private-dns-zone/ptr/main.json index 55828119e3..b6d84769e9 100644 --- a/avm/res/network/private-dns-zone/ptr/main.json +++ b/avm/res/network/private-dns-zone/ptr/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "13360561055754827389" + "templateHash": "4240560893124737328" }, "name": "Private DNS Zone PTR record", "description": "This module deploys a Private DNS Zone PTR record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -117,7 +117,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -162,7 +162,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}/PTR/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/private-dns-zone/soa/README.md b/avm/res/network/private-dns-zone/soa/README.md index 86cfc330db..e2071aed7a 100644 --- a/avm/res/network/private-dns-zone/soa/README.md +++ b/avm/res/network/private-dns-zone/soa/README.md @@ -35,7 +35,7 @@ This module deploys a Private DNS Zone SOA record. | Parameter | Type | Description | | :-- | :-- | :-- | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`soaRecord`](#parameter-soarecord) | object | A SOA record. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | @@ -59,7 +59,7 @@ The name of the parent Private DNS zone. Required if the template is used in a s ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -72,7 +72,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -120,7 +120,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/private-dns-zone/soa/main.bicep b/avm/res/network/private-dns-zone/soa/main.bicep index 2663f8b1b2..098ecf0800 100644 --- a/avm/res/network/private-dns-zone/soa/main.bicep +++ b/avm/res/network/private-dns-zone/soa/main.bicep @@ -17,7 +17,7 @@ param soaRecord object? @description('Optional. The TTL (time-to-live) of the records in the record set.') param ttl int = 3600 -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -47,7 +47,7 @@ resource SOA 'Microsoft.Network/privateDnsZones/SOA@2020-06-01' = { resource SOA_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(SOA.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -72,7 +72,7 @@ output resourceGroupName string = resourceGroup().name // ================ // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/private-dns-zone/soa/main.json b/avm/res/network/private-dns-zone/soa/main.json index 9d51f4ee49..b56471132a 100644 --- a/avm/res/network/private-dns-zone/soa/main.json +++ b/avm/res/network/private-dns-zone/soa/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "2022546465907048440" + "templateHash": "16534327059574132227" }, "name": "Private DNS Zone SOA record", "description": "This module deploys a Private DNS Zone SOA record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -117,7 +117,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -162,7 +162,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}/SOA/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/private-dns-zone/srv/README.md b/avm/res/network/private-dns-zone/srv/README.md index 0c939804e0..3b16840d6e 100644 --- a/avm/res/network/private-dns-zone/srv/README.md +++ b/avm/res/network/private-dns-zone/srv/README.md @@ -35,7 +35,7 @@ This module deploys a Private DNS Zone SRV record. | Parameter | Type | Description | | :-- | :-- | :-- | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`srvRecords`](#parameter-srvrecords) | array | The list of SRV records in the record set. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | @@ -59,7 +59,7 @@ The name of the parent Private DNS zone. Required if the template is used in a s ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -72,7 +72,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -120,7 +120,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/private-dns-zone/srv/main.bicep b/avm/res/network/private-dns-zone/srv/main.bicep index d8555a7575..1e48700ff0 100644 --- a/avm/res/network/private-dns-zone/srv/main.bicep +++ b/avm/res/network/private-dns-zone/srv/main.bicep @@ -17,7 +17,7 @@ param srvRecords array? @description('Optional. The TTL (time-to-live) of the records in the record set.') param ttl int = 3600 -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -47,7 +47,7 @@ resource SRV 'Microsoft.Network/privateDnsZones/SRV@2020-06-01' = { resource SRV_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(SRV.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -72,7 +72,7 @@ output resourceGroupName string = resourceGroup().name // ================ // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/private-dns-zone/srv/main.json b/avm/res/network/private-dns-zone/srv/main.json index c71d4c3911..a5893abae1 100644 --- a/avm/res/network/private-dns-zone/srv/main.json +++ b/avm/res/network/private-dns-zone/srv/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "11017781799470369462" + "templateHash": "10336254327206850957" }, "name": "Private DNS Zone SRV record", "description": "This module deploys a Private DNS Zone SRV record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -117,7 +117,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -162,7 +162,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}/SRV/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/private-dns-zone/tests/e2e/defaults/main.test.bicep b/avm/res/network/private-dns-zone/tests/e2e/defaults/main.test.bicep index 48bab38a03..0c43e4878b 100644 --- a/avm/res/network/private-dns-zone/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/private-dns-zone/tests/e2e/defaults/main.test.bicep @@ -45,18 +45,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' params: { name: '${namePrefix}${serviceShort}001.com' location: 'global' - - // Workaround for PSRule - a: [] - aaaa: [] - cname: [] - mx: [] - ptr: [] - soa: [] - srv: [] - txt: [] - virtualNetworkLinks: [] - lock: {} - roleAssignments: [] } }] diff --git a/avm/res/network/private-dns-zone/tests/e2e/max/main.test.bicep b/avm/res/network/private-dns-zone/tests/e2e/max/main.test.bicep index f015f9530f..360bc32452 100644 --- a/avm/res/network/private-dns-zone/tests/e2e/max/main.test.bicep +++ b/avm/res/network/private-dns-zone/tests/e2e/max/main.test.bicep @@ -62,7 +62,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: 'A_10.240.4.4' roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -89,7 +99,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: 'CNAME_test' roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -112,7 +132,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: 'MX_contoso' roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -130,7 +160,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -140,7 +180,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -150,7 +200,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: '@' roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -172,7 +232,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: 'SRV_contoso' roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -193,7 +263,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: 'TXT_test' roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/network/private-dns-zone/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/private-dns-zone/tests/e2e/waf-aligned/main.test.bicep index 57dc45ab26..423c9f185c 100644 --- a/avm/res/network/private-dns-zone/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/private-dns-zone/tests/e2e/waf-aligned/main.test.bicep @@ -61,16 +61,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' kind: 'CanNotDelete' name: 'myCustomLockName' } - - // Workaround for PS Rule - a: [] - aaaa: [] - cname: [] - mx: [] - ptr: [] - roleAssignments: [] - soa: [] - srv: [] - txt: [] } }] diff --git a/avm/res/network/private-dns-zone/txt/README.md b/avm/res/network/private-dns-zone/txt/README.md index 3b15c2bbae..326c8e92ca 100644 --- a/avm/res/network/private-dns-zone/txt/README.md +++ b/avm/res/network/private-dns-zone/txt/README.md @@ -35,7 +35,7 @@ This module deploys a Private DNS Zone TXT record. | Parameter | Type | Description | | :-- | :-- | :-- | | [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | | [`txtRecords`](#parameter-txtrecords) | array | The list of TXT records in the record set. | @@ -59,7 +59,7 @@ The name of the parent Private DNS zone. Required if the template is used in a s ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -72,7 +72,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -120,7 +120,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/private-dns-zone/txt/main.bicep b/avm/res/network/private-dns-zone/txt/main.bicep index 6bbd25cfaa..1a07549b34 100644 --- a/avm/res/network/private-dns-zone/txt/main.bicep +++ b/avm/res/network/private-dns-zone/txt/main.bicep @@ -17,7 +17,7 @@ param ttl int = 3600 @description('Optional. The list of TXT records in the record set.') param txtRecords 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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -47,7 +47,7 @@ resource TXT 'Microsoft.Network/privateDnsZones/TXT@2020-06-01' = { resource TXT_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(TXT.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -72,7 +72,7 @@ output resourceGroupName string = resourceGroup().name // ================ // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/private-dns-zone/txt/main.json b/avm/res/network/private-dns-zone/txt/main.json index 2f28605b56..e8d2f5044c 100644 --- a/avm/res/network/private-dns-zone/txt/main.json +++ b/avm/res/network/private-dns-zone/txt/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "13485919432065481500" + "templateHash": "14853546982840308619" }, "name": "Private DNS Zone TXT record", "description": "This module deploys a Private DNS Zone TXT record.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -117,7 +117,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -162,7 +162,7 @@ "scope": "[format('Microsoft.Network/privateDnsZones/{0}/TXT/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/private-endpoint/README.md b/avm/res/network/private-endpoint/README.md index a4fdd9de76..ba9d6f73c0 100644 --- a/avm/res/network/private-endpoint/README.md +++ b/avm/res/network/private-endpoint/README.md @@ -54,17 +54,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = serviceResourceId: '' subnetResourceId: '' // Non-required parameters - applicationSecurityGroupResourceIds: [] - customDnsConfigs: [] - customNetworkInterfaceName: '' - ipConfigurations: [] location: '' - lock: {} - manualPrivateLinkServiceConnections: [] - privateDnsZoneGroupName: '' - privateDnsZoneResourceIds: [] - roleAssignments: [] - tags: {} } } ``` @@ -97,38 +87,8 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "value": "" }, // Non-required parameters - "applicationSecurityGroupResourceIds": { - "value": [] - }, - "customDnsConfigs": { - "value": [] - }, - "customNetworkInterfaceName": { - "value": "" - }, - "ipConfigurations": { - "value": [] - }, "location": { "value": "" - }, - "lock": { - "value": {} - }, - "manualPrivateLinkServiceConnections": { - "value": [] - }, - "privateDnsZoneGroupName": { - "value": "" - }, - "privateDnsZoneResourceIds": { - "value": [] - }, - "roleAssignments": { - "value": [] - }, - "tags": { - "value": {} } } } @@ -185,8 +145,6 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = kind: 'CanNotDelete' name: 'myCustomLockName' } - manualPrivateLinkServiceConnections: [] - privateDnsZoneGroupName: 'default' privateDnsZoneResourceIds: [ '' ] @@ -194,7 +152,17 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] tags: { @@ -273,12 +241,6 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "name": "myCustomLockName" } }, - "manualPrivateLinkServiceConnections": { - "value": [] - }, - "privateDnsZoneGroupName": { - "value": "default" - }, "privateDnsZoneResourceIds": { "value": [ "" @@ -289,7 +251,17 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -331,7 +303,6 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = applicationSecurityGroupResourceIds: [ '' ] - customDnsConfigs: [] customNetworkInterfaceName: 'npewaf001nic' ipConfigurations: [ { @@ -348,8 +319,6 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = kind: 'CanNotDelete' name: 'myCustomLockName' } - manualPrivateLinkServiceConnections: [] - privateDnsZoneGroupName: 'default' privateDnsZoneResourceIds: [ '' ] @@ -357,7 +326,17 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] tags: { @@ -402,9 +381,6 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "" ] }, - "customDnsConfigs": { - "value": [] - }, "customNetworkInterfaceName": { "value": "npewaf001nic" }, @@ -429,12 +405,6 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "name": "myCustomLockName" } }, - "manualPrivateLinkServiceConnections": { - "value": [] - }, - "privateDnsZoneGroupName": { - "value": "default" - }, "privateDnsZoneResourceIds": { "value": [ "" @@ -445,7 +415,17 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -489,7 +469,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = | [`manualPrivateLinkServiceConnections`](#parameter-manualprivatelinkserviceconnections) | array | Manual PrivateLink Service Connections. | | [`privateDnsZoneGroupName`](#parameter-privatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`tags`](#parameter-tags) | object | Tags to be applied on all resources/resource groups in this deployment. | ### Parameter: `applicationSecurityGroupResourceIds` @@ -657,7 +637,7 @@ The private DNS zone groups to associate the private endpoint. A DNS zone group ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -670,7 +650,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -718,7 +698,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/private-endpoint/main.bicep b/avm/res/network/private-endpoint/main.bicep index 72caaaeb85..753c62d02a 100644 --- a/avm/res/network/private-endpoint/main.bicep +++ b/avm/res/network/private-endpoint/main.bicep @@ -35,7 +35,7 @@ param location string = resourceGroup().location @description('Optional. The lock settings of the service.') param lock lockType -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') @@ -130,7 +130,7 @@ resource privateEndpoint_lock 'Microsoft.Authorization/locks@2020-05-01' = if (! resource privateEndpoint_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(privateEndpoint.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -158,7 +158,7 @@ output location string = privateEndpoint.location // ================ // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/private-endpoint/main.json b/avm/res/network/private-endpoint/main.json index da4a0ba3b9..0b1a203f91 100644 --- a/avm/res/network/private-endpoint/main.json +++ b/avm/res/network/private-endpoint/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "13477311172998188302" + "templateHash": "11574872241175195302" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -245,7 +245,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -369,7 +369,7 @@ "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep b/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep index 56faf05417..69d2fc7a25 100644 --- a/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep @@ -60,16 +60,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] serviceResourceId: nestedDependencies.outputs.keyVaultResourceId subnetResourceId: nestedDependencies.outputs.subnetResourceId - // Workaround for PSRule - lock: {} - roleAssignments: [] - applicationSecurityGroupResourceIds: [] - customNetworkInterfaceName: '' - privateDnsZoneGroupName: '' - ipConfigurations: [] - customDnsConfigs: [] - privateDnsZoneResourceIds: [] - manualPrivateLinkServiceConnections: [] - tags: {} } }] diff --git a/avm/res/network/private-endpoint/tests/e2e/max/main.test.bicep b/avm/res/network/private-endpoint/tests/e2e/max/main.test.bicep index 3a8cc5081e..5f9f625cfa 100644 --- a/avm/res/network/private-endpoint/tests/e2e/max/main.test.bicep +++ b/avm/res/network/private-endpoint/tests/e2e/max/main.test.bicep @@ -68,7 +68,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -100,8 +110,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Environment: 'Non-Prod' Role: 'DeploymentValidation' } - // Workaround for PSRule - privateDnsZoneGroupName: 'default' - manualPrivateLinkServiceConnections: [] } }] diff --git a/avm/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep index 84638f4b7d..e8c7fb5e3b 100644 --- a/avm/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep @@ -68,7 +68,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } @@ -92,9 +102,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Environment: 'Non-Prod' Role: 'DeploymentValidation' } - // Workaround for PSRule - privateDnsZoneGroupName: 'default' - customDnsConfigs: [] - manualPrivateLinkServiceConnections: [] } }] diff --git a/avm/res/network/public-ip-address/README.md b/avm/res/network/public-ip-address/README.md index 36348d8e81..e6eacfedf6 100644 --- a/avm/res/network/public-ip-address/README.md +++ b/avm/res/network/public-ip-address/README.md @@ -49,15 +49,7 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' = // Required parameters name: 'npiamin001' // Non-required parameters - ddosSettings: '' - diagnosticSettings: '' - dnsSettings: '' location: '' - lock: '' - publicIpPrefixResourceId: '' - roleAssignments: '' - tags: {} - zones: [] } } ``` @@ -79,32 +71,8 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' = "value": "npiamin001" }, // Non-required parameters - "ddosSettings": { - "value": "" - }, - "diagnosticSettings": { - "value": "" - }, - "dnsSettings": { - "value": "" - }, "location": { "value": "" - }, - "lock": { - "value": "" - }, - "publicIpPrefixResourceId": { - "value": "" - }, - "roleAssignments": { - "value": "" - }, - "tags": { - "value": {} - }, - "zones": { - "value": [] } } } @@ -152,7 +120,17 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' = { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] skuName: 'Standard' @@ -228,7 +206,17 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' = { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -298,7 +286,17 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' = { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] skuName: 'Standard' @@ -374,7 +372,17 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' = { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -428,7 +436,7 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' = | [`publicIPAddressVersion`](#parameter-publicipaddressversion) | string | IP address version. | | [`publicIPAllocationMethod`](#parameter-publicipallocationmethod) | string | The public IP address allocation method. | | [`publicIpPrefixResourceId`](#parameter-publicipprefixresourceid) | string | Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`skuName`](#parameter-skuname) | string | Name of a public IP address SKU. | | [`skuTier`](#parameter-skutier) | string | Tier of a public IP address SKU. | | [`tags`](#parameter-tags) | object | Tags of the resource. | @@ -718,7 +726,7 @@ Resource ID of the Public IP Prefix object. This is only needed if you want your ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -731,7 +739,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -779,7 +787,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/network/public-ip-address/main.bicep b/avm/res/network/public-ip-address/main.bicep index 5c0aa654df..d8066099e9 100644 --- a/avm/res/network/public-ip-address/main.bicep +++ b/avm/res/network/public-ip-address/main.bicep @@ -51,7 +51,7 @@ param ddosSettings ddosSettingsType? @description('Optional. Location for all resources.') param location string = resourceGroup().location -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. Enable/Disable usage telemetry for module.') @@ -131,7 +131,7 @@ resource publicIpAddress_lock 'Microsoft.Authorization/locks@2020-05-01' = if (! resource publicIpAddress_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(publicIpAddress.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -188,7 +188,7 @@ output location string = publicIpAddress.location // ================ // type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/network/public-ip-address/main.json b/avm/res/network/public-ip-address/main.json index 5b941ebfae..61268d26f5 100644 --- a/avm/res/network/public-ip-address/main.json +++ b/avm/res/network/public-ip-address/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "11486686724612026983" + "templateHash": "3488076626994379707" }, "name": "Public IP Addresses", "description": "This module deploys a Public IP Address.", @@ -21,7 +21,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -369,7 +369,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "enableTelemetry": { @@ -480,7 +480,7 @@ "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/network/public-ip-address/tests/e2e/defaults/main.test.bicep b/avm/res/network/public-ip-address/tests/e2e/defaults/main.test.bicep index 289a14fc52..b4e293d5f8 100644 --- a/avm/res/network/public-ip-address/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/public-ip-address/tests/e2e/defaults/main.test.bicep @@ -44,14 +44,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' params: { name: '${namePrefix}${serviceShort}001' location: location - // Workaround for PSRule - ddosSettings: null - publicIpPrefixResourceId: null - lock: null - diagnosticSettings: null - roleAssignments: null - dnsSettings: null - tags: {} - zones: [] } }] diff --git a/avm/res/network/public-ip-address/tests/e2e/max/main.test.bicep b/avm/res/network/public-ip-address/tests/e2e/max/main.test.bicep index f7072b63c8..8520b8d043 100644 --- a/avm/res/network/public-ip-address/tests/e2e/max/main.test.bicep +++ b/avm/res/network/public-ip-address/tests/e2e/max/main.test.bicep @@ -74,7 +74,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' publicIPAllocationMethod: 'Static' roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/network/public-ip-address/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/public-ip-address/tests/e2e/waf-aligned/main.test.bicep index fccfb175e2..68f69d0966 100644 --- a/avm/res/network/public-ip-address/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/public-ip-address/tests/e2e/waf-aligned/main.test.bicep @@ -74,7 +74,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' publicIpPrefixResourceId: null roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/operational-insights/workspace/README.md b/avm/res/operational-insights/workspace/README.md index 0ae70ab75b..082b83fb92 100644 --- a/avm/res/operational-insights/workspace/README.md +++ b/avm/res/operational-insights/workspace/README.md @@ -798,7 +798,17 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' = { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] savedSearches: [ @@ -1018,7 +1028,17 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' = { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -1457,7 +1477,7 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' = | [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both. | | [`publicNetworkAccessForIngestion`](#parameter-publicnetworkaccessforingestion) | string | The network access type for accessing Log Analytics ingestion. | | [`publicNetworkAccessForQuery`](#parameter-publicnetworkaccessforquery) | string | The network access type for accessing Log Analytics query. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`savedSearches`](#parameter-savedsearches) | array | Kusto Query Language searches to save. | | [`skuCapacityReservationLevel`](#parameter-skucapacityreservationlevel) | int | The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000. | | [`skuName`](#parameter-skuname) | string | The name of the SKU. | @@ -1740,7 +1760,7 @@ The network access type for accessing Log Analytics query. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -1753,7 +1773,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -1801,7 +1821,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/operational-insights/workspace/main.bicep b/avm/res/operational-insights/workspace/main.bicep index 8404b4b886..e4bd5f2d8f 100644 --- a/avm/res/operational-insights/workspace/main.bicep +++ b/avm/res/operational-insights/workspace/main.bicep @@ -88,7 +88,7 @@ param forceCmkForQuery bool = true @description('Optional. The lock settings of the service.') param lock lockType -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. Tags of the resource.') @@ -302,7 +302,7 @@ resource logAnalyticsWorkspace_lock 'Microsoft.Authorization/locks@2020-05-01' = resource logAnalyticsWorkspace_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(logAnalyticsWorkspace.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -352,7 +352,7 @@ type lockType = { }? type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/operational-insights/workspace/main.json b/avm/res/operational-insights/workspace/main.json index 30db51456c..f600e065b8 100644 --- a/avm/res/operational-insights/workspace/main.json +++ b/avm/res/operational-insights/workspace/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "18390575590170506674" + "templateHash": "18160868089862776194" }, "name": "Log Analytics Workspaces", "description": "This module deploys a Log Analytics Workspace.", @@ -69,7 +69,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -404,7 +404,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -532,7 +532,7 @@ "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/operational-insights/workspace/tests/e2e/max/main.test.bicep b/avm/res/operational-insights/workspace/tests/e2e/max/main.test.bicep index d101d30cb9..35da412776 100644 --- a/avm/res/operational-insights/workspace/tests/e2e/max/main.test.bicep +++ b/avm/res/operational-insights/workspace/tests/e2e/max/main.test.bicep @@ -237,7 +237,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' } roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/power-bi-dedicated/capacity/README.md b/avm/res/power-bi-dedicated/capacity/README.md index 8543b5f948..802b4094b5 100644 --- a/avm/res/power-bi-dedicated/capacity/README.md +++ b/avm/res/power-bi-dedicated/capacity/README.md @@ -53,9 +53,6 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = { } // Non-required parameters location: '' - lock: {} - roleAssignments: [] - tags: {} } } ``` @@ -89,15 +86,6 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = { // Non-required parameters "location": { "value": "" - }, - "lock": { - "value": {} - }, - "roleAssignments": { - "value": [] - }, - "tags": { - "value": {} } } } @@ -140,7 +128,17 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] tags: { @@ -198,7 +196,17 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -243,7 +251,6 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = { kind: 'CanNotDelete' name: 'myCustomLockName' } - roleAssignments: [] tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -289,9 +296,6 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = { "name": "myCustomLockName" } }, - "roleAssignments": { - "value": [] - }, "tags": { "value": { "Environment": "Non-Prod", @@ -325,7 +329,7 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = { | [`location`](#parameter-location) | string | Location for all Resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | | [`mode`](#parameter-mode) | string | Mode of the resource. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`tags`](#parameter-tags) | object | Tags of the resource. | ### Parameter: `enableTelemetry` @@ -397,7 +401,7 @@ Name of the PowerBI Embedded. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -410,7 +414,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -458,7 +462,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/power-bi-dedicated/capacity/main.bicep b/avm/res/power-bi-dedicated/capacity/main.bicep index 2e63b49e77..30ab336a56 100644 --- a/avm/res/power-bi-dedicated/capacity/main.bicep +++ b/avm/res/power-bi-dedicated/capacity/main.bicep @@ -30,7 +30,7 @@ param mode string = 'Gen2' @description('Optional. The lock settings of the service.') param lock lockType -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType var builtInRoleNames = { @@ -90,7 +90,7 @@ resource capacity_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(l resource capacity_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(capacity.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -126,7 +126,7 @@ type lockType = { }? type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') @@ -158,4 +158,3 @@ type skuTpe = { @description('Optional. The tier of the SKU.') tier: ('PBIE_Azure' | 'Premium' | 'AutoPremiumHost')? } - diff --git a/avm/res/power-bi-dedicated/capacity/main.json b/avm/res/power-bi-dedicated/capacity/main.json index 433c0dfe7c..dbd61e1ee5 100644 --- a/avm/res/power-bi-dedicated/capacity/main.json +++ b/avm/res/power-bi-dedicated/capacity/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.22.6.54827", - "templateHash": "4472977690395272155" + "version": "0.23.1.45101", + "templateHash": "2407812006172168612" }, "name": "Power BI Dedicated Capacities", "description": "This module deploys a Power BI Dedicated Capacity.", @@ -46,7 +46,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -203,7 +203,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } } }, @@ -281,7 +281,7 @@ "scope": "[format('Microsoft.PowerBIDedicated/capacities/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.PowerBIDedicated/capacities', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/power-bi-dedicated/capacity/tests/e2e/defaults/main.test.bicep b/avm/res/power-bi-dedicated/capacity/tests/e2e/defaults/main.test.bicep index aacb79bb60..dd902c976a 100644 --- a/avm/res/power-bi-dedicated/capacity/tests/e2e/defaults/main.test.bicep +++ b/avm/res/power-bi-dedicated/capacity/tests/e2e/defaults/main.test.bicep @@ -57,10 +57,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' nestedDependencies.outputs.managedIdentityPrincipalId ] location: location - - // Workaround for PSRule - lock: {} - roleAssignments: [] - tags: {} } }] diff --git a/avm/res/power-bi-dedicated/capacity/tests/e2e/max/main.test.bicep b/avm/res/power-bi-dedicated/capacity/tests/e2e/max/main.test.bicep index f7e0d77fa6..34aa222f46 100644 --- a/avm/res/power-bi-dedicated/capacity/tests/e2e/max/main.test.bicep +++ b/avm/res/power-bi-dedicated/capacity/tests/e2e/max/main.test.bicep @@ -66,7 +66,17 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/power-bi-dedicated/capacity/tests/e2e/waf-aligned/main.test.bicep b/avm/res/power-bi-dedicated/capacity/tests/e2e/waf-aligned/main.test.bicep index f9950220e7..3f907ee3b0 100644 --- a/avm/res/power-bi-dedicated/capacity/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/power-bi-dedicated/capacity/tests/e2e/waf-aligned/main.test.bicep @@ -66,8 +66,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Environment: 'Non-Prod' Role: 'DeploymentValidation' } - - // Workaround for PSRule - roleAssignments: [] } }] diff --git a/avm/res/resource-graph/query/README.md b/avm/res/resource-graph/query/README.md index 7178730ac5..f8ecdbe049 100644 --- a/avm/res/resource-graph/query/README.md +++ b/avm/res/resource-graph/query/README.md @@ -113,7 +113,17 @@ module query 'br/public:avm/res/resource-graph/query:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] tags: { @@ -161,7 +171,17 @@ module query 'br/public:avm/res/resource-graph/query:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -277,7 +297,7 @@ module query 'br/public:avm/res/resource-graph/query:' = { | [`location`](#parameter-location) | string | Location for all resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | | [`queryDescription`](#parameter-querydescription) | string | The description of a graph query. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`tags`](#parameter-tags) | object | Resource tags. | ### Parameter: `enableTelemetry` @@ -342,7 +362,7 @@ The description of a graph query. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -355,7 +375,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -403,7 +423,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/resource-graph/query/main.bicep b/avm/res/resource-graph/query/main.bicep index b608669bf4..489d88681f 100644 --- a/avm/res/resource-graph/query/main.bicep +++ b/avm/res/resource-graph/query/main.bicep @@ -15,7 +15,7 @@ param location string = resourceGroup().location @description('Optional. The lock settings of the service.') param lock lockType -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. Resource tags.') @@ -86,7 +86,7 @@ resource rgQuery 'Microsoft.ResourceGraph/queries@2018-09-01-preview' = { resource rgQuery_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(rgQuery.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -126,7 +126,7 @@ type lockType = { }? type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') diff --git a/avm/res/resource-graph/query/main.json b/avm/res/resource-graph/query/main.json index 884921fa1c..d7dce04e2e 100644 --- a/avm/res/resource-graph/query/main.json +++ b/avm/res/resource-graph/query/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "15120002565372840884" + "templateHash": "4934723615532636044" }, "name": "Resource Graph Queries", "description": "This module deploys a Resource Graph Query.", @@ -46,7 +46,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -128,7 +128,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -224,7 +224,7 @@ "scope": "[format('Microsoft.ResourceGraph/queries/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.ResourceGraph/queries', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/resource-graph/query/tests/e2e/max/main.test.bicep b/avm/res/resource-graph/query/tests/e2e/max/main.test.bicep index f36aa01b11..8782b28c87 100644 --- a/avm/res/resource-graph/query/tests/e2e/max/main.test.bicep +++ b/avm/res/resource-graph/query/tests/e2e/max/main.test.bicep @@ -55,7 +55,17 @@ module testDeployment '../../../main.bicep' = { } roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/search/search-service/README.md b/avm/res/search/search-service/README.md index f0eece5a4c..f5382fe232 100644 --- a/avm/res/search/search-service/README.md +++ b/avm/res/search/search-service/README.md @@ -145,12 +145,17 @@ module searchService 'br/public:avm/res/search/search-service:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' } { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Search Service Contributor' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] sku: 'standard3' @@ -249,12 +254,17 @@ module searchService 'br/public:avm/res/search/search-service:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" }, { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Search Service Contributor" + "roleDefinitionIdOrName": "" } ] }, @@ -592,7 +602,7 @@ module searchService 'br/public:avm/res/search/search-service:' = { | [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | | [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | This value can be set to 'enabled' to avoid breaking changes on existing customer resources and templates. If set to 'disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method. | | [`replicaCount`](#parameter-replicacount) | int | The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`sharedPrivateLinkResources`](#parameter-sharedprivatelinkresources) | array | The sharedPrivateLinkResources to create as part of the search Service. | | [`sku`](#parameter-sku) | string | Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits. | | [`tags`](#parameter-tags) | object | Tags to help categorize the resource in the Azure portal. | @@ -854,7 +864,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | No | string | Optional. The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | No | string | Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | No | array | Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | -| [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | array | 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'. | +| [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | array | Optional. Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | No | string | Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | | [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | Yes | string | Required. Resource ID of the subnet where the endpoint needs to be created. | | [`tags`](#parameter-privateendpointstags) | No | object | Optional. Tags to be applied on all resources/resource groups in this deployment. | @@ -1006,7 +1016,7 @@ Optional. The private DNS zone groups to associate the private endpoint with. A ### Parameter: `privateEndpoints.roleAssignments` -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'. +Optional. Array of role assignments to create. - Required: No - Type: array @@ -1055,7 +1065,7 @@ The number of replicas in the search service. If specified, it must be a value b ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -1068,7 +1078,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -1116,7 +1126,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/search/search-service/main.bicep b/avm/res/search/search-service/main.bicep index 92b07b574c..42a3bb2afc 100644 --- a/avm/res/search/search-service/main.bicep +++ b/avm/res/search/search-service/main.bicep @@ -65,7 +65,7 @@ param publicNetworkAccess string = 'enabled' @maxValue(12) param replicaCount int = 1 -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits.') @@ -190,7 +190,7 @@ resource searchService_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!em resource searchService_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(searchService.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -278,7 +278,7 @@ type lockType = { }? type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') @@ -355,7 +355,7 @@ type privateEndpointType = { @description('Optional. Specify the type of lock.') lock: lockType - @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\'.') + @description('Optional. Array of role assignments to create.') roleAssignments: roleAssignmentType @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') diff --git a/avm/res/search/search-service/main.json b/avm/res/search/search-service/main.json index 135b3a1b67..4a7b90621d 100644 --- a/avm/res/search/search-service/main.json +++ b/avm/res/search/search-service/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "10662812229242750213" + "templateHash": "7881856021577467097" }, "name": "Search Services", "description": "This module deploys a Search Service.", @@ -59,7 +59,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -264,7 +264,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -515,7 +515,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "sku": { @@ -658,7 +658,7 @@ "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Search/searchServices', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/search/search-service/tests/e2e/max/main.test.bicep b/avm/res/search/search-service/tests/e2e/max/main.test.bicep index 5143ee2da1..4155009d7a 100644 --- a/avm/res/search/search-service/tests/e2e/max/main.test.bicep +++ b/avm/res/search/search-service/tests/e2e/max/main.test.bicep @@ -84,12 +84,17 @@ module testDeployment '../../../main.bicep' = { } roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } { - roleDefinitionIdOrName: 'Search Service Contributor' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } diff --git a/avm/res/sql/server/README.md b/avm/res/sql/server/README.md index 86287e7a35..60c7c09863 100644 --- a/avm/res/sql/server/README.md +++ b/avm/res/sql/server/README.md @@ -269,7 +269,17 @@ module server 'br/public:avm/res/sql/server:' = { { principalId: '' principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' } ] securityAlertPolicies: [ @@ -432,7 +442,17 @@ module server 'br/public:avm/res/sql/server:' = { { "principalId": "", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" } ] }, @@ -1107,7 +1127,7 @@ module server 'br/public:avm/res/sql/server:' = { | [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | | [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | 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 neither firewall rules nor virtual network rules are set. | | [`restrictOutboundNetworkAccess`](#parameter-restrictoutboundnetworkaccess) | string | Whether or not to restrict outbound network access for this server. | -| [`roleAssignments`](#parameter-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'. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`securityAlertPolicies`](#parameter-securityalertpolicies) | array | The security alert policies to create in the server. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`virtualNetworkRules`](#parameter-virtualnetworkrules) | array | The virtual network rules to create in the server. | @@ -1284,7 +1304,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | No | string | Optional. The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | No | string | Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | No | array | Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | -| [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | array | 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'. | +| [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | array | Optional. Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | No | string | Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | | [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | Yes | string | Required. Resource ID of the subnet where the endpoint needs to be created. | | [`tags`](#parameter-privateendpointstags) | No | object | Optional. Tags to be applied on all resources/resource groups in this deployment. | @@ -1436,7 +1456,7 @@ Optional. The private DNS zone groups to associate the private endpoint with. A ### Parameter: `privateEndpoints.roleAssignments` -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'. +Optional. Array of role assignments to create. - Required: No - Type: array @@ -1494,7 +1514,7 @@ Whether or not to restrict outbound network access for this server. ### Parameter: `roleAssignments` -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'. +Array of role assignments to create. - Required: No - Type: array @@ -1507,7 +1527,7 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' | [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | | [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | | [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | -| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | ### Parameter: `roleAssignments.condition` @@ -1555,7 +1575,7 @@ Optional. The principal type of the assigned principal ID. ### Parameter: `roleAssignments.roleDefinitionIdOrName` -Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: Yes - Type: string diff --git a/avm/res/sql/server/main.bicep b/avm/res/sql/server/main.bicep index e397cc2bf0..ed6d64e517 100644 --- a/avm/res/sql/server/main.bicep +++ b/avm/res/sql/server/main.bicep @@ -24,7 +24,7 @@ param primaryUserAssignedIdentityId string = '' @description('Optional. The lock settings of the service.') param lock lockType -@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\'.') +@description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @description('Optional. Tags of the resource.') @@ -163,7 +163,7 @@ resource server_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(loc resource server_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(server.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -369,7 +369,7 @@ type lockType = { }? type roleAssignmentType = { - @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') roleDefinitionIdOrName: string @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') @@ -446,7 +446,7 @@ type privateEndpointType = { @description('Optional. Specify the type of lock.') lock: lockType - @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\'.') + @description('Optional. Array of role assignments to create.') roleAssignments: roleAssignmentType @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') diff --git a/avm/res/sql/server/main.json b/avm/res/sql/server/main.json index a89c9c28fe..4ae2fd096c 100644 --- a/avm/res/sql/server/main.json +++ b/avm/res/sql/server/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "12295213353677593935" + "templateHash": "11876144653623707899" }, "name": "Azure SQL Servers", "description": "This module deploys an Azure SQL Server.", @@ -69,7 +69,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -274,7 +274,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -353,7 +353,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -557,7 +557,7 @@ "scope": "[format('Microsoft.Sql/servers/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Sql/servers', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/sql/server/tests/e2e/max/main.test.bicep b/avm/res/sql/server/tests/e2e/max/main.test.bicep index 49194820d3..2b7d23f477 100644 --- a/avm/res/sql/server/tests/e2e/max/main.test.bicep +++ b/avm/res/sql/server/tests/e2e/max/main.test.bicep @@ -79,7 +79,17 @@ module testDeployment '../../../main.bicep' = { location: location roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') principalId: nestedDependencies.outputs.managedIdentityPrincipalId principalType: 'ServicePrincipal' } From 88080e729e9fc0c411e3b425ab123a1a75a79e98 Mon Sep 17 00:00:00 2001 From: Elena Batanero <46710322+elbatane@users.noreply.github.com> Date: Mon, 27 Nov 2023 18:37:06 +0100 Subject: [PATCH 06/22] feat: Added module virtual-network (#595) ## Description Added module virtual-network - converted from CARML. If you haven't already, read the full [contribution guide](https://github.com/Azure/bicep-registry-modules/blob/main/CONTRIBUTING.md). The guide may have changed since the last time you read it, so please double-check. Once you are done and ready to submit your PR, edit the PR description and run through the relevant checklist below. Enable GitHub Worksflows in your fork to enable auto-generation of assets with our [GitHub Action](/.github/workflows/push-auto-generate.yml). To trigger GitHub Actions after auto-generation, [add a GitHub PAT](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) as a secret in your forked repository called `PAT`. ## Adding a new module - [x] A proposal has been submitted and approved. - [ ] I have included "Closes #{module_proposal_issue_number}" in the PR description. - [x] I have run `brm validate` locally to verify the module files. - [x] I have run deployment tests locally to ensure the module is deployable. ## Updating an existing module - [ ] This is a bug fix: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] I have run `brm validate` locally to verify the module files. - [ ] I have run deployment tests locally to ensure the module is deployable. - [ ] I have read the [Updating an existing module](https://github.com/Azure/bicep-registry-modules/blob/main/CONTRIBUTING.md#updating-an-existing-module) section in the contributing guide and updated the `version.json` file properly: - [ ] The PR contains backwards compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`. - [ ] The PR contains backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] The PR contains breaking changes, and I have bumped the MAJOR version in `version.json`. - [ ] I have updated the examples in README with the latest module version number. --------- Co-authored-by: Elena Batanero Garcia Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> Co-authored-by: Alexander Sehr --- .../avm.res.network.virtual-network.yml | 81 ++ avm/res/network/virtual-network/README.md | 1070 ++++++++++++++++ avm/res/network/virtual-network/main.bicep | 334 +++++ avm/res/network/virtual-network/main.json | 1131 +++++++++++++++++ .../network/virtual-network/subnet/README.md | 248 ++++ .../network/virtual-network/subnet/main.bicep | 152 +++ .../network/virtual-network/subnet/main.json | 295 +++++ .../tests/e2e/defaults/main.test.bicep | 49 + .../tests/e2e/max/dependencies.bicep | 163 +++ .../tests/e2e/max/main.test.bicep | 167 +++ .../tests/e2e/vnetPeering/dependencies.bicep | 158 +++ .../tests/e2e/vnetPeering/main.test.bicep | 92 ++ .../tests/e2e/waf-aligned/dependencies.bicep | 163 +++ .../tests/e2e/waf-aligned/main.test.bicep | 160 +++ avm/res/network/virtual-network/version.json | 7 + .../virtual-network-peering/README.md | 108 ++ .../virtual-network-peering/main.bicep | 55 + .../virtual-network-peering/main.json | 110 ++ 18 files changed, 4543 insertions(+) create mode 100644 .github/workflows/avm.res.network.virtual-network.yml create mode 100644 avm/res/network/virtual-network/README.md create mode 100644 avm/res/network/virtual-network/main.bicep create mode 100644 avm/res/network/virtual-network/main.json create mode 100644 avm/res/network/virtual-network/subnet/README.md create mode 100644 avm/res/network/virtual-network/subnet/main.bicep create mode 100644 avm/res/network/virtual-network/subnet/main.json create mode 100644 avm/res/network/virtual-network/tests/e2e/defaults/main.test.bicep create mode 100644 avm/res/network/virtual-network/tests/e2e/max/dependencies.bicep create mode 100644 avm/res/network/virtual-network/tests/e2e/max/main.test.bicep create mode 100644 avm/res/network/virtual-network/tests/e2e/vnetPeering/dependencies.bicep create mode 100644 avm/res/network/virtual-network/tests/e2e/vnetPeering/main.test.bicep create mode 100644 avm/res/network/virtual-network/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/res/network/virtual-network/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/res/network/virtual-network/version.json create mode 100644 avm/res/network/virtual-network/virtual-network-peering/README.md create mode 100644 avm/res/network/virtual-network/virtual-network-peering/main.bicep create mode 100644 avm/res/network/virtual-network/virtual-network-peering/main.json diff --git a/.github/workflows/avm.res.network.virtual-network.yml b/.github/workflows/avm.res.network.virtual-network.yml new file mode 100644 index 0000000000..6bddce3b9a --- /dev/null +++ b/.github/workflows/avm.res.network.virtual-network.yml @@ -0,0 +1,81 @@ +name: "avm.res.network.virtual-network" + +on: + schedule: + - cron: "0 12 1/15 * *" # Bi-Weekly Test (on 1st & 15th of month) + 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 + + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.network.virtual-network.yml" + - "avm/res/network/virtual-network/**" + - "avm/utilities/pipelines/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/network/virtual-network" + workflowPath: ".github/workflows/avm.res.network.virtual-network.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-20.04 + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get parameter file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Module" + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/res/network/virtual-network/README.md b/avm/res/network/virtual-network/README.md new file mode 100644 index 0000000000..96571ac9ee --- /dev/null +++ b/avm/res/network/virtual-network/README.md @@ -0,0 +1,1070 @@ +# Virtual Networks `[Microsoft.Network/virtualNetworks]` + +This module deploys a Virtual Network (vNet). + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Notes](#Notes) + +## Resource Types + +| 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/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/virtualNetworks` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/virtualNetworks) | +| `Microsoft.Network/virtualNetworks/subnets` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/virtualNetworks/subnets) | +| `Microsoft.Network/virtualNetworks/virtualNetworkPeerings` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/virtualNetworks/virtualNetworkPeerings) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/virtual-network:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [Deploying a bi-directional peering](#example-3-deploying-a-bi-directional-peering) +- [WAF-aligned](#example-4-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module virtualNetwork 'br/public:avm/res/network/virtual-network:' = { + name: '${uniqueString(deployment().name, location)}-test-nvnmin' + params: { + // Required parameters + addressPrefixes: [ + '10.0.0.0/16' + ] + name: 'nvnmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +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 + "addressPrefixes": { + "value": [ + "10.0.0.0/16" + ] + }, + "name": { + "value": "nvnmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module virtualNetwork 'br/public:avm/res/network/virtual-network:' = { + name: '${uniqueString(deployment().name, location)}-test-nvnmax' + params: { + // Required parameters + addressPrefixes: [ + '' + ] + name: 'nvnmax001' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + dnsServers: [ + '10.0.1.4' + '10.0.1.5' + ] + flowTimeoutInMinutes: 20 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'az-subnet-x-001' + networkSecurityGroupResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + routeTableResourceId: '' + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + { + service: 'Microsoft.Sql' + } + ] + } + { + addressPrefix: '' + delegations: [ + { + name: 'netappDel' + properties: { + serviceName: 'Microsoft.Netapp/volumes' + } + } + ] + name: 'az-subnet-x-002' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '' + name: 'az-subnet-x-003' + networkSecurityGroupResourceId: '' + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +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 + "addressPrefixes": { + "value": [ + "" + ] + }, + "name": { + "value": "nvnmax001" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "dnsServers": { + "value": [ + "10.0.1.4", + "10.0.1.5" + ] + }, + "flowTimeoutInMinutes": { + "value": 20 + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ] + }, + "subnets": { + "value": [ + { + "addressPrefix": "", + "name": "GatewaySubnet" + }, + { + "addressPrefix": "", + "name": "az-subnet-x-001", + "networkSecurityGroupResourceId": "", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], + "routeTableResourceId": "", + "serviceEndpoints": [ + { + "service": "Microsoft.Storage" + }, + { + "service": "Microsoft.Sql" + } + ] + }, + { + "addressPrefix": "", + "delegations": [ + { + "name": "netappDel", + "properties": { + "serviceName": "Microsoft.Netapp/volumes" + } + } + ], + "name": "az-subnet-x-002", + "networkSecurityGroupResourceId": "" + }, + { + "addressPrefix": "", + "name": "az-subnet-x-003", + "networkSecurityGroupResourceId": "", + "privateEndpointNetworkPolicies": "Disabled", + "privateLinkServiceNetworkPolicies": "Enabled" + }, + { + "addressPrefix": "", + "name": "AzureBastionSubnet", + "networkSecurityGroupResourceId": "" + }, + { + "addressPrefix": "", + "name": "AzureFirewallSubnet" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +### Example 3: _Deploying a bi-directional peering_ + +This instance deploys the module with both an inbound and outbound peering. + + +

+ +via Bicep module + +```bicep +module virtualNetwork 'br/public:avm/res/network/virtual-network:' = { + name: '${uniqueString(deployment().name, location)}-test-nvnpeer' + params: { + // Required parameters + addressPrefixes: [ + '10.1.0.0/24' + ] + name: 'nvnpeer001' + // Non-required parameters + location: '' + peerings: [ + { + allowForwardedTraffic: true + allowGatewayTransit: false + allowVirtualNetworkAccess: true + remotePeeringAllowForwardedTraffic: true + remotePeeringAllowVirtualNetworkAccess: true + remotePeeringEnabled: true + remotePeeringName: 'customName' + remoteVirtualNetworkId: '' + useRemoteGateways: false + } + ] + subnets: [ + { + addressPrefix: '10.1.0.0/26' + name: 'GatewaySubnet' + } + { + addressPrefix: '10.1.0.64/26' + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '10.1.0.128/26' + name: 'AzureFirewallSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +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 + "addressPrefixes": { + "value": [ + "10.1.0.0/24" + ] + }, + "name": { + "value": "nvnpeer001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "peerings": { + "value": [ + { + "allowForwardedTraffic": true, + "allowGatewayTransit": false, + "allowVirtualNetworkAccess": true, + "remotePeeringAllowForwardedTraffic": true, + "remotePeeringAllowVirtualNetworkAccess": true, + "remotePeeringEnabled": true, + "remotePeeringName": "customName", + "remoteVirtualNetworkId": "", + "useRemoteGateways": false + } + ] + }, + "subnets": { + "value": [ + { + "addressPrefix": "10.1.0.0/26", + "name": "GatewaySubnet" + }, + { + "addressPrefix": "10.1.0.64/26", + "name": "AzureBastionSubnet", + "networkSecurityGroupResourceId": "" + }, + { + "addressPrefix": "10.1.0.128/26", + "name": "AzureFirewallSubnet" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +### Example 4: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module virtualNetwork 'br/public:avm/res/network/virtual-network:' = { + name: '${uniqueString(deployment().name, location)}-test-nvnwaf' + params: { + // Required parameters + addressPrefixes: [ + '' + ] + name: 'nvnwaf001' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + dnsServers: [ + '10.0.1.4' + '10.0.1.5' + ] + flowTimeoutInMinutes: 20 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'az-subnet-x-001' + networkSecurityGroupResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + routeTableResourceId: '' + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + { + service: 'Microsoft.Sql' + } + ] + } + { + addressPrefix: '' + delegations: [ + { + name: 'netappDel' + properties: { + serviceName: 'Microsoft.Netapp/volumes' + } + } + ] + name: 'az-subnet-x-002' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '' + name: 'az-subnet-x-003' + networkSecurityGroupResourceId: '' + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +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 + "addressPrefixes": { + "value": [ + "" + ] + }, + "name": { + "value": "nvnwaf001" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "dnsServers": { + "value": [ + "10.0.1.4", + "10.0.1.5" + ] + }, + "flowTimeoutInMinutes": { + "value": 20 + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "subnets": { + "value": [ + { + "addressPrefix": "", + "name": "GatewaySubnet" + }, + { + "addressPrefix": "", + "name": "az-subnet-x-001", + "networkSecurityGroupResourceId": "", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], + "routeTableResourceId": "", + "serviceEndpoints": [ + { + "service": "Microsoft.Storage" + }, + { + "service": "Microsoft.Sql" + } + ] + }, + { + "addressPrefix": "", + "delegations": [ + { + "name": "netappDel", + "properties": { + "serviceName": "Microsoft.Netapp/volumes" + } + } + ], + "name": "az-subnet-x-002", + "networkSecurityGroupResourceId": "" + }, + { + "addressPrefix": "", + "name": "az-subnet-x-003", + "networkSecurityGroupResourceId": "", + "privateEndpointNetworkPolicies": "Disabled", + "privateLinkServiceNetworkPolicies": "Enabled" + }, + { + "addressPrefix": "", + "name": "AzureBastionSubnet", + "networkSecurityGroupResourceId": "" + }, + { + "addressPrefix": "", + "name": "AzureFirewallSubnet" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefixes`](#parameter-addressprefixes) | array | An Array of 1 or more IP Address Prefixes for the Virtual Network. | +| [`name`](#parameter-name) | string | The Virtual Network (vNet) Name. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ddosProtectionPlanResourceId`](#parameter-ddosprotectionplanresourceid) | string | Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`dnsServers`](#parameter-dnsservers) | array | DNS Servers associated to the Virtual Network. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`flowTimeoutInMinutes`](#parameter-flowtimeoutinminutes) | int | The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`peerings`](#parameter-peerings) | array | Virtual Network Peerings configurations. | +| [`roleAssignments`](#parameter-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'. | +| [`subnets`](#parameter-subnets) | array | An Array of subnets to deploy to the Virtual Network. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`vnetEncryption`](#parameter-vnetencryption) | bool | Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property. | +| [`vnetEncryptionEnforcement`](#parameter-vnetencryptionenforcement) | string | If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled. | + +### Parameter: `addressPrefixes` + +An Array of 1 or more IP Address Prefixes for the Virtual Network. +- Required: Yes +- Type: array + +### Parameter: `ddosProtectionPlanResourceId` + +Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription. +- Required: No +- Type: string +- Default: `''` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. +- Required: No +- Type: array + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | No | string | 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. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | No | string | 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. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | No | string | Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | No | array | Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | No | string | Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | No | array | Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. | +| [`name`](#parameter-diagnosticsettingsname) | No | string | Optional. The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | No | string | 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. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | No | string | 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. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +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. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +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. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: `[AzureDiagnostics, Dedicated]` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. + +- Required: No +- Type: array + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | No | string | Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | No | string | Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to 'AllLogs' to collect all logs. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to 'AllLogs' to collect all logs. + +- Required: No +- Type: string + + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. + +- Required: No +- Type: array + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | Yes | string | Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to 'AllMetrics' to collect all metrics. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to 'AllMetrics' to collect all metrics. + +- Required: Yes +- Type: string + + +### Parameter: `diagnosticSettings.name` + +Optional. The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +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. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +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. + +- Required: No +- Type: string + +### Parameter: `dnsServers` + +DNS Servers associated to the Virtual Network. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `flowTimeoutInMinutes` + +The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null. +- Required: No +- Type: int +- Default: `0` + +### Parameter: `location` + +Location for all resources. +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. +- Required: No +- Type: object + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`kind`](#parameter-lockkind) | No | string | Optional. Specify the type of lock. | +| [`name`](#parameter-lockname) | No | string | Optional. Specify the name of lock. | + +### Parameter: `lock.kind` + +Optional. Specify the type of lock. + +- Required: No +- Type: string +- Allowed: `[CanNotDelete, None, ReadOnly]` + +### Parameter: `lock.name` + +Optional. Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `name` + +The Virtual Network (vNet) Name. +- Required: Yes +- Type: string + +### Parameter: `peerings` + +Virtual Network Peerings configurations. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `roleAssignments` + +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'. +- Required: No +- Type: array + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`condition`](#parameter-roleassignmentscondition) | No | string | 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" | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | No | string | Optional. Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | No | string | Optional. The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | +| [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | + +### Parameter: `roleAssignments.condition` + +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" + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Optional. Version of the condition. + +- Required: No +- Type: string +- Allowed: `[2.0]` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +Optional. The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +Optional. The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalId` + +Required. The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.principalType` + +Optional. The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: `[Device, ForeignGroup, Group, ServicePrincipal, User]` + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. + +- Required: Yes +- Type: string + +### Parameter: `subnets` + +An Array of subnets to deploy to the Virtual Network. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `tags` + +Tags of the resource. +- Required: No +- Type: object + +### Parameter: `vnetEncryption` + +Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property. +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `vnetEncryptionEnforcement` + +If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled. +- Required: No +- Type: string +- Default: `'AllowUnencrypted'` +- Allowed: + ```Bicep + [ + 'AllowUnencrypted' + 'DropUnencrypted' + ] + ``` + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the virtual network. | +| `resourceGroupName` | string | The resource group the virtual network was deployed into. | +| `resourceId` | string | The resource ID of the virtual network. | +| `subnetNames` | array | The names of the deployed subnets. | +| `subnetResourceIds` | array | The resource IDs of the deployed subnets. | + +## Cross-referenced modules + +_None_ + +## Notes + +### Considerations + +The network security group and route table resources must reside in the same resource group as the virtual network. + +### Parameter Usage: `peerings` + +As the virtual network peering array allows you to deploy not only a one-way but also two-way peering (i.e reverse), you can use the following ***additional*** properties on top of what is documented in _[virtualNetworkPeering](virtual-network-peering/README.md)_. + +| Parameter Name | Type | Default Value | Possible Values | Description | +| :-- | :-- | :-- | :-- | :-- | +| `remotePeeringEnabled` | bool | `false` | | Optional. Set to true to also deploy the reverse peering for the configured remote virtual networks to the local network | +| `remotePeeringName` | string | `'${last(split(peering.remoteVirtualNetworkId, '/'))}-${name}'` | | Optional. The Name of Vnet Peering resource. If not provided, default value will be - | +| `remotePeeringAllowForwardedTraffic` | bool | `true` | | Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. | +| `remotePeeringAllowGatewayTransit` | bool | `false` | | Optional. If gateway links can be used in remote virtual networking to link to this virtual network. | +| `remotePeeringAllowVirtualNetworkAccess` | bool | `true` | | Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. | +| `remotePeeringDoNotVerifyRemoteGateways` | bool | `true` | | Optional. If we need to verify the provisioning state of the remote gateway. | +| `remotePeeringUseRemoteGateways` | bool | `false` | | Optional. If remote gateways can be used on this virtual network. If the flag is set to `true`, and allowGatewayTransit on local peering is also `true`, virtual network will use gateways of local virtual network for transit. Only one peering can have this flag set to `true`. This flag cannot be set if virtual network already has a gateway. | diff --git a/avm/res/network/virtual-network/main.bicep b/avm/res/network/virtual-network/main.bicep new file mode 100644 index 0000000000..7268fc4b7e --- /dev/null +++ b/avm/res/network/virtual-network/main.bicep @@ -0,0 +1,334 @@ +metadata name = 'Virtual Networks' +metadata description = 'This module deploys a Virtual Network (vNet).' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The Virtual Network (vNet) Name.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Required. An Array of 1 or more IP Address Prefixes for the Virtual Network.') +param addressPrefixes array + +@description('Optional. An Array of subnets to deploy to the Virtual Network.') +param subnets array = [] + +@description('Optional. DNS Servers associated to the Virtual Network.') +param dnsServers array = [] + +@description('Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it\'s left blank, DDoS protection will not be configured. If it\'s provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription.') +param ddosProtectionPlanResourceId string = '' + +@description('Optional. Virtual Network Peerings configurations.') +param peerings array = [] + +@description('Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property.') +param vnetEncryption bool = false + +@allowed([ + 'AllowUnencrypted' + 'DropUnencrypted' +]) +@description('Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled.') +param vnetEncryptionEnforcement string = 'AllowUnencrypted' + +@maxValue(30) +@description('Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null.') +param flowTimeoutInMinutes int = 0 + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. The lock settings of the service.') +param lock lockType + +@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 roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var dnsServersVar = { + dnsServers: array(dnsServers) +} + +var ddosProtectionPlan = { + id: ddosProtectionPlanResourceId +} + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + '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') +} + +// ============ // +// Dependencies // +// ============ // + +resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-virtualnetwork.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: name + location: location + tags: tags + properties: { + addressSpace: { + addressPrefixes: addressPrefixes + } + ddosProtectionPlan: !empty(ddosProtectionPlanResourceId) ? ddosProtectionPlan : null + dhcpOptions: !empty(dnsServers) ? dnsServersVar : null + enableDdosProtection: !empty(ddosProtectionPlanResourceId) + encryption: vnetEncryption == true ? { + enabled: vnetEncryption + enforcement: vnetEncryptionEnforcement + } : null + flowTimeoutInMinutes: flowTimeoutInMinutes != 0 ? flowTimeoutInMinutes : null + subnets: [for subnet in subnets: { + name: subnet.name + properties: { + addressPrefix: subnet.addressPrefix + addressPrefixes: contains(subnet, 'addressPrefixes') ? subnet.addressPrefixes : [] + applicationGatewayIPConfigurations: contains(subnet, 'applicationGatewayIPConfigurations') ? subnet.applicationGatewayIPConfigurations : [] + delegations: contains(subnet, 'delegations') ? subnet.delegations : [] + ipAllocations: contains(subnet, 'ipAllocations') ? subnet.ipAllocations : [] + natGateway: contains(subnet, 'natGatewayResourceId') ? { + id: subnet.natGatewayResourceId + } : null + networkSecurityGroup: contains(subnet, 'networkSecurityGroupResourceId') ? { + id: subnet.networkSecurityGroupResourceId + } : null + privateEndpointNetworkPolicies: contains(subnet, 'privateEndpointNetworkPolicies') ? subnet.privateEndpointNetworkPolicies : null + privateLinkServiceNetworkPolicies: contains(subnet, 'privateLinkServiceNetworkPolicies') ? subnet.privateLinkServiceNetworkPolicies : null + routeTable: contains(subnet, 'routeTableResourceId') ? { + id: subnet.routeTableResourceId + } : null + serviceEndpoints: contains(subnet, 'serviceEndpoints') ? subnet.serviceEndpoints : [] + serviceEndpointPolicies: contains(subnet, 'serviceEndpointPolicies') ? subnet.serviceEndpointPolicies : [] + } + }] + } +} + +//NOTE Start: ------------------------------------ +// The below module (virtualNetwork_subnets) is a duplicate of the child resource (subnets) defined in the parent module (virtualNetwork). +// The reason it exists so that deployment validation tests can be performed on the child module (subnets), in case that module needed to be deployed alone outside of this template. +// The reason for duplication is due to the current design for the (virtualNetworks) resource from Azure, where if the child module (subnets) does not exist within it, causes +// an issue, where the child resource (subnets) gets all of its properties removed, hence not as 'idempotent' as it should be. See https://github.com/Azure/azure-quickstart-templates/issues/2786 for more details. +// You can safely remove the below child module (virtualNetwork_subnets) in your consumption of the module (virtualNetworks) to reduce the template size and duplication. +//NOTE End : ------------------------------------ + +module virtualNetwork_subnets 'subnet/main.bicep' = [for (subnet, index) in subnets: { + name: '${uniqueString(deployment().name, location)}-subnet-${index}' + params: { + virtualNetworkName: virtualNetwork.name + name: subnet.name + addressPrefix: subnet.addressPrefix + addressPrefixes: contains(subnet, 'addressPrefixes') ? subnet.addressPrefixes : [] + applicationGatewayIPConfigurations: contains(subnet, 'applicationGatewayIPConfigurations') ? subnet.applicationGatewayIPConfigurations : [] + delegations: contains(subnet, 'delegations') ? subnet.delegations : [] + ipAllocations: contains(subnet, 'ipAllocations') ? subnet.ipAllocations : [] + natGatewayResourceId: contains(subnet, 'natGatewayResourceId') ? subnet.natGatewayResourceId : '' + networkSecurityGroupResourceId: contains(subnet, 'networkSecurityGroupResourceId') ? subnet.networkSecurityGroupResourceId : '' + privateEndpointNetworkPolicies: contains(subnet, 'privateEndpointNetworkPolicies') ? subnet.privateEndpointNetworkPolicies : '' + privateLinkServiceNetworkPolicies: contains(subnet, 'privateLinkServiceNetworkPolicies') ? subnet.privateLinkServiceNetworkPolicies : '' + roleAssignments: contains(subnet, 'roleAssignments') ? subnet.roleAssignments : [] + routeTableResourceId: contains(subnet, 'routeTableResourceId') ? subnet.routeTableResourceId : '' + serviceEndpointPolicies: contains(subnet, 'serviceEndpointPolicies') ? subnet.serviceEndpointPolicies : [] + serviceEndpoints: contains(subnet, 'serviceEndpoints') ? subnet.serviceEndpoints : [] + } +}] + +// Local to Remote peering +module virtualNetwork_peering_local 'virtual-network-peering/main.bicep' = [for (peering, index) in peerings: { + name: '${uniqueString(deployment().name, location)}-virtualNetworkPeering-local-${index}' + params: { + localVnetName: virtualNetwork.name + remoteVirtualNetworkId: peering.remoteVirtualNetworkId + name: contains(peering, 'name') ? peering.name : '${name}-${last(split(peering.remoteVirtualNetworkId, '/'))}' + allowForwardedTraffic: contains(peering, 'allowForwardedTraffic') ? peering.allowForwardedTraffic : true + allowGatewayTransit: contains(peering, 'allowGatewayTransit') ? peering.allowGatewayTransit : false + allowVirtualNetworkAccess: contains(peering, 'allowVirtualNetworkAccess') ? peering.allowVirtualNetworkAccess : true + doNotVerifyRemoteGateways: contains(peering, 'doNotVerifyRemoteGateways') ? peering.doNotVerifyRemoteGateways : true + useRemoteGateways: contains(peering, 'useRemoteGateways') ? peering.useRemoteGateways : false + } +}] + +// Remote to local peering (reverse) +module virtualNetwork_peering_remote 'virtual-network-peering/main.bicep' = [for (peering, index) in peerings: if (contains(peering, 'remotePeeringEnabled') ? peering.remotePeeringEnabled == true : false) { + name: '${uniqueString(deployment().name, location)}-virtualNetworkPeering-remote-${index}' + scope: resourceGroup(split(peering.remoteVirtualNetworkId, '/')[2], split(peering.remoteVirtualNetworkId, '/')[4]) + params: { + localVnetName: last(split(peering.remoteVirtualNetworkId, '/'))! + remoteVirtualNetworkId: virtualNetwork.id + name: contains(peering, 'remotePeeringName') ? peering.remotePeeringName : '${last(split(peering.remoteVirtualNetworkId, '/'))}-${name}' + allowForwardedTraffic: contains(peering, 'remotePeeringAllowForwardedTraffic') ? peering.remotePeeringAllowForwardedTraffic : true + allowGatewayTransit: contains(peering, 'remotePeeringAllowGatewayTransit') ? peering.remotePeeringAllowGatewayTransit : false + allowVirtualNetworkAccess: contains(peering, 'remotePeeringAllowVirtualNetworkAccess') ? peering.remotePeeringAllowVirtualNetworkAccess : true + doNotVerifyRemoteGateways: contains(peering, 'remotePeeringDoNotVerifyRemoteGateways') ? peering.remotePeeringDoNotVerifyRemoteGateways : true + useRemoteGateways: contains(peering, 'remotePeeringUseRemoteGateways') ? peering.remotePeeringUseRemoteGateways : false + } +}] + +resource virtualNetwork_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' ? 'Cannot delete resource or child resources.' : 'Cannot delete or modify the resource or child resources.' + } + scope: virtualNetwork +} + +resource virtualNetwork_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: diagnosticSetting.?metricCategories ?? [ + { + category: 'AllMetrics' + timeGrain: null + enabled: true + } + ] + logs: diagnosticSetting.?logCategoriesAndGroups ?? [ + { + categoryGroup: 'AllLogs' + enabled: true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: virtualNetwork +}] + +resource virtualNetwork_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { + name: guid(virtualNetwork.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) + properties: { + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: virtualNetwork +}] + +@description('The resource group the virtual network was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the virtual network.') +output resourceId string = virtualNetwork.id + +@description('The name of the virtual network.') +output name string = virtualNetwork.name + +@description('The names of the deployed subnets.') +output subnetNames array = [for subnet in subnets: subnet.name] + +@description('The resource IDs of the deployed subnets.') +output subnetResourceIds array = [for subnet in subnets: az.resourceId('Microsoft.Network/virtualNetworks/subnets', name, subnet.name)] + +@description('The location the resource was deployed into.') +output location string = virtualNetwork.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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"') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to \'\' to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to \'AllLogs\' to collect all logs.') + categoryGroup: string? + }[]? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to \'\' to disable log collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to \'AllMetrics\' to collect all metrics.') + category: string + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @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.') + workspaceResourceId: string? + + @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.') + storageAccountResourceId: 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.') + eventHubAuthorizationRuleResourceId: 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.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? diff --git a/avm/res/network/virtual-network/main.json b/avm/res/network/virtual-network/main.json new file mode 100644 index 0000000000..5868b76060 --- /dev/null +++ b/avm/res/network/virtual-network/main.json @@ -0,0 +1,1131 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.21.1.54444", + "templateHash": "7839005038128499146" + }, + "name": "Virtual Networks", + "description": "This module deploys a Virtual Network (vNet).", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to 'AllLogs' to collect all logs." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to '' to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to 'AllMetrics' to collect all metrics." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to '' to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "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." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "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." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "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." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "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." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Virtual Network (vNet) Name." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "Required. An Array of 1 or more IP Address Prefixes for the Virtual Network." + } + }, + "subnets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An Array of subnets to deploy to the Virtual Network." + } + }, + "dnsServers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. DNS Servers associated to the Virtual Network." + } + }, + "ddosProtectionPlanResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." + } + }, + "peerings": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Virtual Network Peerings configurations." + } + }, + "vnetEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." + } + }, + "vnetEncryptionEnforcement": { + "type": "string", + "defaultValue": "AllowUnencrypted", + "allowedValues": [ + "AllowUnencrypted", + "DropUnencrypted" + ], + "metadata": { + "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." + } + }, + "flowTimeoutInMinutes": { + "type": "int", + "defaultValue": 0, + "maxValue": 30, + "metadata": { + "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "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'." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "dnsServersVar": { + "dnsServers": "[array(parameters('dnsServers'))]" + }, + "ddosProtectionPlan": { + "id": "[parameters('ddosProtectionPlanResourceId')]" + }, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "virtualNetwork": { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "subnets", + "count": "[length(parameters('subnets'))]", + "input": { + "name": "[parameters('subnets')[copyIndex('subnets')].name]", + "properties": { + "addressPrefix": "[parameters('subnets')[copyIndex('subnets')].addressPrefix]", + "addressPrefixes": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'addressPrefixes'), parameters('subnets')[copyIndex('subnets')].addressPrefixes, createArray())]", + "applicationGatewayIPConfigurations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'applicationGatewayIPConfigurations'), parameters('subnets')[copyIndex('subnets')].applicationGatewayIPConfigurations, createArray())]", + "delegations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'delegations'), parameters('subnets')[copyIndex('subnets')].delegations, createArray())]", + "ipAllocations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'ipAllocations'), parameters('subnets')[copyIndex('subnets')].ipAllocations, createArray())]", + "natGateway": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'natGatewayResourceId'), createObject('id', parameters('subnets')[copyIndex('subnets')].natGatewayResourceId), null())]", + "networkSecurityGroup": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'networkSecurityGroupResourceId'), createObject('id', parameters('subnets')[copyIndex('subnets')].networkSecurityGroupResourceId), null())]", + "privateEndpointNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'privateEndpointNetworkPolicies'), parameters('subnets')[copyIndex('subnets')].privateEndpointNetworkPolicies, null())]", + "privateLinkServiceNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'privateLinkServiceNetworkPolicies'), parameters('subnets')[copyIndex('subnets')].privateLinkServiceNetworkPolicies, null())]", + "routeTable": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'routeTableResourceId'), createObject('id', parameters('subnets')[copyIndex('subnets')].routeTableResourceId), null())]", + "serviceEndpoints": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'serviceEndpoints'), parameters('subnets')[copyIndex('subnets')].serviceEndpoints, createArray())]", + "serviceEndpointPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'serviceEndpointPolicies'), parameters('subnets')[copyIndex('subnets')].serviceEndpointPolicies, createArray())]" + } + } + } + ], + "addressSpace": { + "addressPrefixes": "[parameters('addressPrefixes')]" + }, + "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), variables('ddosProtectionPlan'), null())]", + "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), variables('dnsServersVar'), null())]", + "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", + "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]" + } + }, + "virtualNetwork_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_diagnosticSettings": { + "copy": { + "name": "virtualNetwork_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "metrics": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics', 'timeGrain', null(), 'enabled', true())))]", + "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'AllLogs', 'enabled', true())))]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_roleAssignments": { + "copy": { + "name": "virtualNetwork_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_subnets": { + "copy": { + "name": "virtualNetwork_subnets", + "count": "[length(parameters('subnets'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-subnet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualNetworkName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('subnets')[copyIndex()].name]" + }, + "addressPrefix": { + "value": "[parameters('subnets')[copyIndex()].addressPrefix]" + }, + "addressPrefixes": "[if(contains(parameters('subnets')[copyIndex()], 'addressPrefixes'), createObject('value', parameters('subnets')[copyIndex()].addressPrefixes), createObject('value', createArray()))]", + "applicationGatewayIPConfigurations": "[if(contains(parameters('subnets')[copyIndex()], 'applicationGatewayIPConfigurations'), createObject('value', parameters('subnets')[copyIndex()].applicationGatewayIPConfigurations), createObject('value', createArray()))]", + "delegations": "[if(contains(parameters('subnets')[copyIndex()], 'delegations'), createObject('value', parameters('subnets')[copyIndex()].delegations), createObject('value', createArray()))]", + "ipAllocations": "[if(contains(parameters('subnets')[copyIndex()], 'ipAllocations'), createObject('value', parameters('subnets')[copyIndex()].ipAllocations), createObject('value', createArray()))]", + "natGatewayResourceId": "[if(contains(parameters('subnets')[copyIndex()], 'natGatewayResourceId'), createObject('value', parameters('subnets')[copyIndex()].natGatewayResourceId), createObject('value', ''))]", + "networkSecurityGroupResourceId": "[if(contains(parameters('subnets')[copyIndex()], 'networkSecurityGroupResourceId'), createObject('value', parameters('subnets')[copyIndex()].networkSecurityGroupResourceId), createObject('value', ''))]", + "privateEndpointNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex()], 'privateEndpointNetworkPolicies'), createObject('value', parameters('subnets')[copyIndex()].privateEndpointNetworkPolicies), createObject('value', ''))]", + "privateLinkServiceNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex()], 'privateLinkServiceNetworkPolicies'), createObject('value', parameters('subnets')[copyIndex()].privateLinkServiceNetworkPolicies), createObject('value', ''))]", + "roleAssignments": "[if(contains(parameters('subnets')[copyIndex()], 'roleAssignments'), createObject('value', parameters('subnets')[copyIndex()].roleAssignments), createObject('value', createArray()))]", + "routeTableResourceId": "[if(contains(parameters('subnets')[copyIndex()], 'routeTableResourceId'), createObject('value', parameters('subnets')[copyIndex()].routeTableResourceId), createObject('value', ''))]", + "serviceEndpointPolicies": "[if(contains(parameters('subnets')[copyIndex()], 'serviceEndpointPolicies'), createObject('value', parameters('subnets')[copyIndex()].serviceEndpointPolicies), createObject('value', createArray()))]", + "serviceEndpoints": "[if(contains(parameters('subnets')[copyIndex()], 'serviceEndpoints'), createObject('value', parameters('subnets')[copyIndex()].serviceEndpoints), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.21.1.54444", + "templateHash": "16295395838729593723" + }, + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Optional. The Name of the subnet resource." + } + }, + "virtualNetworkName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. The address prefix for the subnet." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "routeTableResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpoints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "delegations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The delegations to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Disabled", + "Enabled", + "" + ], + "metadata": { + "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Disabled", + "Enabled", + "" + ], + "metadata": { + "description": "Optional. enable or disable apply network policies on private link service in the subnet." + } + }, + "addressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of address prefixes for the subnet." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "ipAllocations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of IpAllocation which reference this subnet." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "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'." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "virtualNetwork": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2023-04-01", + "name": "[parameters('virtualNetworkName')]" + }, + "subnet": { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "properties": { + "addressPrefix": "[parameters('addressPrefix')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", + "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", + "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", + "serviceEndpoints": "[parameters('serviceEndpoints')]", + "delegations": "[parameters('delegations')]", + "privateEndpointNetworkPolicies": "[if(not(empty(parameters('privateEndpointNetworkPolicies'))), parameters('privateEndpointNetworkPolicies'), null())]", + "privateLinkServiceNetworkPolicies": "[if(not(empty(parameters('privateLinkServiceNetworkPolicies'))), parameters('privateLinkServiceNetworkPolicies'), null())]", + "addressPrefixes": "[parameters('addressPrefixes')]", + "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", + "ipAllocations": "[parameters('ipAllocations')]", + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "subnet_roleAssignments": { + "copy": { + "name": "subnet_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}/subnets/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "subnet" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + }, + "subnetAddressPrefix": { + "type": "string", + "metadata": { + "description": "The address prefix for the subnet." + }, + "value": "[reference('subnet').addressPrefix]" + }, + "subnetAddressPrefixes": { + "type": "array", + "metadata": { + "description": "List of address prefixes for the subnet." + }, + "value": "[if(not(empty(parameters('addressPrefixes'))), reference('subnet').addressPrefixes, createArray())]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_peering_local": { + "copy": { + "name": "virtualNetwork_peering_local", + "count": "[length(parameters('peerings'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[parameters('name')]" + }, + "remoteVirtualNetworkId": { + "value": "[parameters('peerings')[copyIndex()].remoteVirtualNetworkId]" + }, + "name": "[if(contains(parameters('peerings')[copyIndex()], 'name'), createObject('value', parameters('peerings')[copyIndex()].name), createObject('value', format('{0}-{1}', parameters('name'), last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')))))]", + "allowForwardedTraffic": "[if(contains(parameters('peerings')[copyIndex()], 'allowForwardedTraffic'), createObject('value', parameters('peerings')[copyIndex()].allowForwardedTraffic), createObject('value', true()))]", + "allowGatewayTransit": "[if(contains(parameters('peerings')[copyIndex()], 'allowGatewayTransit'), createObject('value', parameters('peerings')[copyIndex()].allowGatewayTransit), createObject('value', false()))]", + "allowVirtualNetworkAccess": "[if(contains(parameters('peerings')[copyIndex()], 'allowVirtualNetworkAccess'), createObject('value', parameters('peerings')[copyIndex()].allowVirtualNetworkAccess), createObject('value', true()))]", + "doNotVerifyRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'doNotVerifyRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].doNotVerifyRemoteGateways), createObject('value', true()))]", + "useRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'useRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].useRemoteGateways), createObject('value', false()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.21.1.54444", + "templateHash": "10220824930947117349" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "metadata": { + "description": "Optional. The Name of Vnet Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_peering_remote": { + "copy": { + "name": "virtualNetwork_peering_remote", + "count": "[length(parameters('peerings'))]" + }, + "condition": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringEnabled'), equals(parameters('peerings')[copyIndex()].remotePeeringEnabled, true()), false())]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')[2]]", + "resourceGroup": "[split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/'))]" + }, + "remoteVirtualNetworkId": { + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringName'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringName), createObject('value', format('{0}-{1}', last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')), parameters('name'))))]", + "allowForwardedTraffic": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringAllowForwardedTraffic'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringAllowForwardedTraffic), createObject('value', true()))]", + "allowGatewayTransit": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringAllowGatewayTransit'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringAllowGatewayTransit), createObject('value', false()))]", + "allowVirtualNetworkAccess": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringAllowVirtualNetworkAccess), createObject('value', true()))]", + "doNotVerifyRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringDoNotVerifyRemoteGateways), createObject('value', true()))]", + "useRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringUseRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringUseRemoteGateways), createObject('value', false()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.21.1.54444", + "templateHash": "10220824930947117349" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "metadata": { + "description": "Optional. The Name of Vnet Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network." + }, + "value": "[parameters('name')]" + }, + "subnetNames": { + "type": "array", + "metadata": { + "description": "The names of the deployed subnets." + }, + "copy": { + "count": "[length(parameters('subnets'))]", + "input": "[parameters('subnets')[copyIndex()].name]" + } + }, + "subnetResourceIds": { + "type": "array", + "metadata": { + "description": "The resource IDs of the deployed subnets." + }, + "copy": { + "count": "[length(parameters('subnets'))]", + "input": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('name'), parameters('subnets')[copyIndex()].name)]" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetwork', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/res/network/virtual-network/subnet/README.md b/avm/res/network/virtual-network/subnet/README.md new file mode 100644 index 0000000000..db5e5fa1f0 --- /dev/null +++ b/avm/res/network/virtual-network/subnet/README.md @@ -0,0 +1,248 @@ +# Virtual Network Subnets `[Microsoft.Network/virtualNetworks/subnets]` + +This module deploys a Virtual Network Subnet. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Notes](#Notes) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/virtualNetworks/subnets` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/virtualNetworks/subnets) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefix`](#parameter-addressprefix) | string | The address prefix for the subnet. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`virtualNetworkName`](#parameter-virtualnetworkname) | string | The name of the parent virtual network. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefixes`](#parameter-addressprefixes) | array | List of address prefixes for the subnet. | +| [`applicationGatewayIPConfigurations`](#parameter-applicationgatewayipconfigurations) | array | Application gateway IP configurations of virtual network resource. | +| [`delegations`](#parameter-delegations) | array | The delegations to enable on the subnet. | +| [`ipAllocations`](#parameter-ipallocations) | array | Array of IpAllocation which reference this subnet. | +| [`name`](#parameter-name) | string | The Name of the subnet resource. | +| [`natGatewayResourceId`](#parameter-natgatewayresourceid) | string | The resource ID of the NAT Gateway to use for the subnet. | +| [`networkSecurityGroupResourceId`](#parameter-networksecuritygroupresourceid) | string | The resource ID of the network security group to assign to the subnet. | +| [`privateEndpointNetworkPolicies`](#parameter-privateendpointnetworkpolicies) | string | enable or disable apply network policies on private endpoint in the subnet. | +| [`privateLinkServiceNetworkPolicies`](#parameter-privatelinkservicenetworkpolicies) | string | enable or disable apply network policies on private link service in the subnet. | +| [`roleAssignments`](#parameter-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'. | +| [`routeTableResourceId`](#parameter-routetableresourceid) | string | The resource ID of the route table to assign to the subnet. | +| [`serviceEndpointPolicies`](#parameter-serviceendpointpolicies) | array | An array of service endpoint policies. | +| [`serviceEndpoints`](#parameter-serviceendpoints) | array | The service endpoints to enable on the subnet. | + +### Parameter: `addressPrefix` + +The address prefix for the subnet. +- Required: Yes +- Type: string + +### Parameter: `addressPrefixes` + +List of address prefixes for the subnet. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `applicationGatewayIPConfigurations` + +Application gateway IP configurations of virtual network resource. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `delegations` + +The delegations to enable on the subnet. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `ipAllocations` + +Array of IpAllocation which reference this subnet. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `name` + +The Name of the subnet resource. +- Required: Yes +- Type: string + +### Parameter: `natGatewayResourceId` + +The resource ID of the NAT Gateway to use for the subnet. +- Required: No +- Type: string +- Default: `''` + +### Parameter: `networkSecurityGroupResourceId` + +The resource ID of the network security group to assign to the subnet. +- Required: No +- Type: string +- Default: `''` + +### Parameter: `privateEndpointNetworkPolicies` + +enable or disable apply network policies on private endpoint in the subnet. +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `privateLinkServiceNetworkPolicies` + +enable or disable apply network policies on private link service in the subnet. +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `roleAssignments` + +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'. +- Required: No +- Type: array + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`condition`](#parameter-roleassignmentscondition) | No | string | 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" | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | No | string | Optional. Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | No | string | Optional. The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | +| [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | + +### Parameter: `roleAssignments.condition` + +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" + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Optional. Version of the condition. + +- Required: No +- Type: string +- Allowed: `[2.0]` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +Optional. The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +Optional. The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalId` + +Required. The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.principalType` + +Optional. The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: `[Device, ForeignGroup, Group, ServicePrincipal, User]` + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. + +- Required: Yes +- Type: string + +### Parameter: `routeTableResourceId` + +The resource ID of the route table to assign to the subnet. +- Required: No +- Type: string +- Default: `''` + +### Parameter: `serviceEndpointPolicies` + +An array of service endpoint policies. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `serviceEndpoints` + +The service endpoints to enable on the subnet. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `virtualNetworkName` + +The name of the parent virtual network. Required if the template is used in a standalone deployment. +- Required: Yes +- Type: string + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the virtual network peering. | +| `resourceGroupName` | string | The resource group the virtual network peering was deployed into. | +| `resourceId` | string | The resource ID of the virtual network peering. | +| `subnetAddressPrefix` | string | The address prefix for the subnet. | +| `subnetAddressPrefixes` | array | List of address prefixes for the subnet. | + +## Cross-referenced modules + +_None_ + +## Notes + +The `privateEndpointNetworkPolicies` property must be set to disabled for subnets that contain private endpoints. It confirms that NSGs rules will not apply to private endpoints (currently not supported, [reference](https://learn.microsoft.com/en-us/azure/private-link/private-endpoint-overview#limitations)). Default Value when not specified is "Enabled". diff --git a/avm/res/network/virtual-network/subnet/main.bicep b/avm/res/network/virtual-network/subnet/main.bicep new file mode 100644 index 0000000000..818252102b --- /dev/null +++ b/avm/res/network/virtual-network/subnet/main.bicep @@ -0,0 +1,152 @@ +metadata name = 'Virtual Network Subnets' +metadata description = 'This module deploys a Virtual Network Subnet.' +metadata owner = 'Azure/module-maintainers' + +@description('Optional. The Name of the subnet resource.') +param name string + +@description('Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment.') +param virtualNetworkName string + +@description('Required. The address prefix for the subnet.') +param addressPrefix string + +@description('Optional. The resource ID of the network security group to assign to the subnet.') +param networkSecurityGroupResourceId string = '' + +@description('Optional. The resource ID of the route table to assign to the subnet.') +param routeTableResourceId string = '' + +@description('Optional. The service endpoints to enable on the subnet.') +param serviceEndpoints array = [] + +@description('Optional. The delegations to enable on the subnet.') +param delegations array = [] + +@description('Optional. The resource ID of the NAT Gateway to use for the subnet.') +param natGatewayResourceId string = '' + +@description('Optional. enable or disable apply network policies on private endpoint in the subnet.') +@allowed([ + 'Disabled' + 'Enabled' + '' +]) +param privateEndpointNetworkPolicies string = '' + +@description('Optional. enable or disable apply network policies on private link service in the subnet.') +@allowed([ + 'Disabled' + 'Enabled' + '' +]) +param privateLinkServiceNetworkPolicies string = '' + +@description('Optional. List of address prefixes for the subnet.') +param addressPrefixes array = [] + +@description('Optional. Application gateway IP configurations of virtual network resource.') +param applicationGatewayIPConfigurations array = [] + +@description('Optional. Array of IpAllocation which reference this subnet.') +param ipAllocations array = [] + +@description('Optional. An array of service endpoint policies.') +param serviceEndpointPolicies 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 roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + '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 virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' existing = { + name: virtualNetworkName +} + +resource subnet 'Microsoft.Network/virtualNetworks/subnets@2023-04-01' = { + name: name + parent: virtualNetwork + properties: { + addressPrefix: addressPrefix + networkSecurityGroup: !empty(networkSecurityGroupResourceId) ? { + id: networkSecurityGroupResourceId + } : null + routeTable: !empty(routeTableResourceId) ? { + id: routeTableResourceId + } : null + natGateway: !empty(natGatewayResourceId) ? { + id: natGatewayResourceId + } : null + serviceEndpoints: serviceEndpoints + delegations: delegations + privateEndpointNetworkPolicies: !empty(privateEndpointNetworkPolicies) ? any(privateEndpointNetworkPolicies) : null + privateLinkServiceNetworkPolicies: !empty(privateLinkServiceNetworkPolicies) ? any(privateLinkServiceNetworkPolicies) : null + addressPrefixes: addressPrefixes + applicationGatewayIPConfigurations: applicationGatewayIPConfigurations + ipAllocations: ipAllocations + serviceEndpointPolicies: serviceEndpointPolicies + } +} + +resource subnet_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { + name: guid(subnet.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) + properties: { + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: subnet +}] + +@description('The resource group the virtual network peering was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the virtual network peering.') +output name string = subnet.name + +@description('The resource ID of the virtual network peering.') +output resourceId string = subnet.id + +@description('The address prefix for the subnet.') +output subnetAddressPrefix string = subnet.properties.addressPrefix + +@description('List of address prefixes for the subnet.') +output subnetAddressPrefixes array = !empty(addressPrefixes) ? subnet.properties.addressPrefixes : [] + +// =============== // +// Definitions // +// =============== // + +type roleAssignmentType = { + @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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"') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/res/network/virtual-network/subnet/main.json b/avm/res/network/virtual-network/subnet/main.json new file mode 100644 index 0000000000..50448165d9 --- /dev/null +++ b/avm/res/network/virtual-network/subnet/main.json @@ -0,0 +1,295 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.21.1.54444", + "templateHash": "16295395838729593723" + }, + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Optional. The Name of the subnet resource." + } + }, + "virtualNetworkName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. The address prefix for the subnet." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "routeTableResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpoints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "delegations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The delegations to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Disabled", + "Enabled", + "" + ], + "metadata": { + "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Disabled", + "Enabled", + "" + ], + "metadata": { + "description": "Optional. enable or disable apply network policies on private link service in the subnet." + } + }, + "addressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of address prefixes for the subnet." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "ipAllocations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of IpAllocation which reference this subnet." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "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'." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "virtualNetwork": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2023-04-01", + "name": "[parameters('virtualNetworkName')]" + }, + "subnet": { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "properties": { + "addressPrefix": "[parameters('addressPrefix')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", + "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", + "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", + "serviceEndpoints": "[parameters('serviceEndpoints')]", + "delegations": "[parameters('delegations')]", + "privateEndpointNetworkPolicies": "[if(not(empty(parameters('privateEndpointNetworkPolicies'))), parameters('privateEndpointNetworkPolicies'), null())]", + "privateLinkServiceNetworkPolicies": "[if(not(empty(parameters('privateLinkServiceNetworkPolicies'))), parameters('privateLinkServiceNetworkPolicies'), null())]", + "addressPrefixes": "[parameters('addressPrefixes')]", + "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", + "ipAllocations": "[parameters('ipAllocations')]", + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "subnet_roleAssignments": { + "copy": { + "name": "subnet_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}/subnets/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "subnet" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + }, + "subnetAddressPrefix": { + "type": "string", + "metadata": { + "description": "The address prefix for the subnet." + }, + "value": "[reference('subnet').addressPrefix]" + }, + "subnetAddressPrefixes": { + "type": "array", + "metadata": { + "description": "List of address prefixes for the subnet." + }, + "value": "[if(not(empty(parameters('addressPrefixes'))), reference('subnet').addressPrefixes, createArray())]" + } + } +} \ No newline at end of file diff --git a/avm/res/network/virtual-network/tests/e2e/defaults/main.test.bicep b/avm/res/network/virtual-network/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..be4081119d --- /dev/null +++ b/avm/res/network/virtual-network/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,49 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworks-${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 = 'nvnmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + addressPrefixes: [ + '10.0.0.0/16' + ] + } +}] diff --git a/avm/res/network/virtual-network/tests/e2e/max/dependencies.bicep b/avm/res/network/virtual-network/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..b7275d12a1 --- /dev/null +++ b/avm/res/network/virtual-network/tests/e2e/max/dependencies.bicep @@ -0,0 +1,163 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Route Table to create.') +param routeTableName string + +@description('Required. The name of the Network Security Group to create.') +param networkSecurityGroupName string + +@description('Required. The name of the Bastion Network Security Group to create.') +param networkSecurityGroupBastionName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource routeTable 'Microsoft.Network/routeTables@2023-04-01' = { + name: routeTableName + location: location +} + +resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: networkSecurityGroupName + location: location +} + +resource networkSecurityGroupBastion 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: networkSecurityGroupBastionName + location: location + properties: { + securityRules: [ + { + name: 'AllowHttpsInbound' + properties: { + priority: 120 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'Internet' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowGatewayManagerInbound' + properties: { + priority: 130 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'GatewayManager' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowAzureLoadBalancerInbound' + properties: { + priority: 140 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'AzureLoadBalancer' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowBastionHostCommunication' + properties: { + priority: 150 + protocol: '*' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'AllowSshOutbound' + properties: { + priority: 100 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '22' + '3389' + ] + } + } + { + name: 'AllowAzureCloudOutbound' + properties: { + priority: 110 + protocol: 'Tcp' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'AzureCloud' + destinationPortRange: '443' + } + } + { + name: 'AllowBastionCommunication' + properties: { + priority: 120 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'AllowHttpOutbound' + properties: { + priority: 130 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'Internet' + destinationPortRange: '80' + } + } + ] + } +} + +@description('The resource ID of the created Route Table.') +output routeTableResourceId string = routeTable.id + +@description('The resource ID of the created Network Security Group.') +output networkSecurityGroupResourceId string = networkSecurityGroup.id + +@description('The resource ID of the created Bastion Network Security Group.') +output networkSecurityGroupBastionResourceId string = networkSecurityGroupBastion.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/network/virtual-network/tests/e2e/max/main.test.bicep b/avm/res/network/virtual-network/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..c47e25b964 --- /dev/null +++ b/avm/res/network/virtual-network/tests/e2e/max/main.test.bicep @@ -0,0 +1,167 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworks-${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 = 'nvnmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + location: location + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + routeTableName: 'dep-${namePrefix}-rt-${serviceShort}' + networkSecurityGroupName: 'dep-${namePrefix}-nsg-${serviceShort}' + networkSecurityGroupBastionName: 'dep-${namePrefix}-nsg-bastion-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +var addressPrefix = '10.0.0.0/16' +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + addressPrefixes: [ + addressPrefix + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + dnsServers: [ + '10.0.1.4' + '10.0.1.5' + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + flowTimeoutInMinutes: 20 + subnets: [ + { + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + name: 'GatewaySubnet' + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 1) + name: '${namePrefix}-az-subnet-x-001' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupResourceId + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + routeTableResourceId: nestedDependencies.outputs.routeTableResourceId + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + { + service: 'Microsoft.Sql' + } + ] + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 2) + delegations: [ + { + name: 'netappDel' + properties: { + serviceName: 'Microsoft.Netapp/volumes' + } + } + ] + name: '${namePrefix}-az-subnet-x-002' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupResourceId + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 3) + name: '${namePrefix}-az-subnet-x-003' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupResourceId + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 4) + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupBastionResourceId + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 5) + name: 'AzureFirewallSubnet' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +}] diff --git a/avm/res/network/virtual-network/tests/e2e/vnetPeering/dependencies.bicep b/avm/res/network/virtual-network/tests/e2e/vnetPeering/dependencies.bicep new file mode 100644 index 0000000000..041d29aa3a --- /dev/null +++ b/avm/res/network/virtual-network/tests/e2e/vnetPeering/dependencies.bicep @@ -0,0 +1,158 @@ +@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 Bastion Network Security Group to create.') +param networkSecurityGroupBastionName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource networkSecurityGroupBastion 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: networkSecurityGroupBastionName + location: location + properties: { + securityRules: [ + { + name: 'AllowHttpsInbound' + properties: { + priority: 120 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'Internet' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowGatewayManagerInbound' + properties: { + priority: 130 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'GatewayManager' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowAzureLoadBalancerInbound' + properties: { + priority: 140 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'AzureLoadBalancer' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowBastionHostCommunication' + properties: { + priority: 150 + protocol: '*' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'AllowSshOutbound' + properties: { + priority: 100 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '22' + '3389' + ] + } + } + { + name: 'AllowAzureCloudOutbound' + properties: { + priority: 110 + protocol: 'Tcp' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'AzureCloud' + destinationPortRange: '443' + } + } + { + name: 'AllowBastionCommunication' + properties: { + priority: 120 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'AllowHttpOutbound' + properties: { + priority: 130 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'Internet' + destinationPortRange: '80' + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created Bastion Network Security Group.') +output networkSecurityGroupBastionResourceId string = networkSecurityGroupBastion.id diff --git a/avm/res/network/virtual-network/tests/e2e/vnetPeering/main.test.bicep b/avm/res/network/virtual-network/tests/e2e/vnetPeering/main.test.bicep new file mode 100644 index 0000000000..4beef2ae9e --- /dev/null +++ b/avm/res/network/virtual-network/tests/e2e/vnetPeering/main.test.bicep @@ -0,0 +1,92 @@ +targetScope = 'subscription' + +metadata name = 'Deploying a bi-directional peering' +metadata description = 'This instance deploys the module with both an inbound and outbound peering.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworks-${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 = 'nvnpeer' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + location: location + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + networkSecurityGroupBastionName: 'dep-${namePrefix}-nsg-bastion-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + addressPrefixes: [ + '10.1.0.0/24' + ] + subnets: [ + { + addressPrefix: '10.1.0.0/26' + name: 'GatewaySubnet' + } + { + addressPrefix: '10.1.0.64/26' + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupBastionResourceId + } + { + addressPrefix: '10.1.0.128/26' + name: 'AzureFirewallSubnet' + } + ] + peerings: [ + { + allowForwardedTraffic: true + allowGatewayTransit: false + allowVirtualNetworkAccess: true + remotePeeringAllowForwardedTraffic: true + remotePeeringAllowVirtualNetworkAccess: true + remotePeeringEnabled: true + remotePeeringName: 'customName' + remoteVirtualNetworkId: nestedDependencies.outputs.virtualNetworkResourceId + useRemoteGateways: false + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +}] diff --git a/avm/res/network/virtual-network/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/network/virtual-network/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 0000000000..b7275d12a1 --- /dev/null +++ b/avm/res/network/virtual-network/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,163 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Route Table to create.') +param routeTableName string + +@description('Required. The name of the Network Security Group to create.') +param networkSecurityGroupName string + +@description('Required. The name of the Bastion Network Security Group to create.') +param networkSecurityGroupBastionName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource routeTable 'Microsoft.Network/routeTables@2023-04-01' = { + name: routeTableName + location: location +} + +resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: networkSecurityGroupName + location: location +} + +resource networkSecurityGroupBastion 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: networkSecurityGroupBastionName + location: location + properties: { + securityRules: [ + { + name: 'AllowHttpsInbound' + properties: { + priority: 120 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'Internet' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowGatewayManagerInbound' + properties: { + priority: 130 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'GatewayManager' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowAzureLoadBalancerInbound' + properties: { + priority: 140 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'AzureLoadBalancer' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowBastionHostCommunication' + properties: { + priority: 150 + protocol: '*' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'AllowSshOutbound' + properties: { + priority: 100 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '22' + '3389' + ] + } + } + { + name: 'AllowAzureCloudOutbound' + properties: { + priority: 110 + protocol: 'Tcp' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'AzureCloud' + destinationPortRange: '443' + } + } + { + name: 'AllowBastionCommunication' + properties: { + priority: 120 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'AllowHttpOutbound' + properties: { + priority: 130 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'Internet' + destinationPortRange: '80' + } + } + ] + } +} + +@description('The resource ID of the created Route Table.') +output routeTableResourceId string = routeTable.id + +@description('The resource ID of the created Network Security Group.') +output networkSecurityGroupResourceId string = networkSecurityGroup.id + +@description('The resource ID of the created Bastion Network Security Group.') +output networkSecurityGroupBastionResourceId string = networkSecurityGroupBastion.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/network/virtual-network/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/virtual-network/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..57d01ea281 --- /dev/null +++ b/avm/res/network/virtual-network/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,160 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworks-${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 = 'nvnwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + routeTableName: 'dep-${namePrefix}-rt-${serviceShort}' + networkSecurityGroupName: 'dep-${namePrefix}-nsg-${serviceShort}' + networkSecurityGroupBastionName: 'dep-${namePrefix}-nsg-bastion-${serviceShort}' + location: location + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +var addressPrefix = '10.0.0.0/16' +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + addressPrefixes: [ + addressPrefix + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + dnsServers: [ + '10.0.1.4' + '10.0.1.5' + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + flowTimeoutInMinutes: 20 + subnets: [ + { + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + name: 'GatewaySubnet' + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 1) + name: '${namePrefix}-az-subnet-x-001' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupResourceId + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + routeTableResourceId: nestedDependencies.outputs.routeTableResourceId + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + { + service: 'Microsoft.Sql' + } + ] + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 2) + delegations: [ + { + name: 'netappDel' + properties: { + serviceName: 'Microsoft.Netapp/volumes' + } + } + ] + name: '${namePrefix}-az-subnet-x-002' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupResourceId + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 3) + name: '${namePrefix}-az-subnet-x-003' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupResourceId + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 4) + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupBastionResourceId + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 5) + name: 'AzureFirewallSubnet' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +}] diff --git a/avm/res/network/virtual-network/version.json b/avm/res/network/virtual-network/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/res/network/virtual-network/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/res/network/virtual-network/virtual-network-peering/README.md b/avm/res/network/virtual-network/virtual-network-peering/README.md new file mode 100644 index 0000000000..2f192e6fe9 --- /dev/null +++ b/avm/res/network/virtual-network/virtual-network-peering/README.md @@ -0,0 +1,108 @@ +# Virtual Network Peerings `[Microsoft.Network/virtualNetworks/virtualNetworkPeerings]` + +This module deploys a Virtual Network Peering. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/virtualNetworks/virtualNetworkPeerings` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/virtualNetworks/virtualNetworkPeerings) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`remoteVirtualNetworkId`](#parameter-remotevirtualnetworkid) | string | The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`localVnetName`](#parameter-localvnetname) | string | The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowForwardedTraffic`](#parameter-allowforwardedtraffic) | bool | Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true. | +| [`allowGatewayTransit`](#parameter-allowgatewaytransit) | bool | If gateway links can be used in remote virtual networking to link to this virtual network. Default is false. | +| [`allowVirtualNetworkAccess`](#parameter-allowvirtualnetworkaccess) | bool | Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true. | +| [`doNotVerifyRemoteGateways`](#parameter-donotverifyremotegateways) | bool | If we need to verify the provisioning state of the remote gateway. Default is true. | +| [`name`](#parameter-name) | string | The Name of Vnet Peering resource. If not provided, default value will be localVnetName-remoteVnetName. | +| [`useRemoteGateways`](#parameter-useremotegateways) | bool | If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false. | + +### Parameter: `allowForwardedTraffic` + +Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true. +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `allowGatewayTransit` + +If gateway links can be used in remote virtual networking to link to this virtual network. Default is false. +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `allowVirtualNetworkAccess` + +Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true. +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `doNotVerifyRemoteGateways` + +If we need to verify the provisioning state of the remote gateway. Default is true. +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `localVnetName` + +The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment. +- Required: Yes +- Type: string + +### Parameter: `name` + +The Name of Vnet Peering resource. If not provided, default value will be localVnetName-remoteVnetName. +- Required: No +- Type: string +- Default: `[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]` + +### Parameter: `remoteVirtualNetworkId` + +The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID. +- Required: Yes +- Type: string + +### Parameter: `useRemoteGateways` + +If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false. +- Required: No +- Type: bool +- Default: `False` + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the virtual network peering. | +| `resourceGroupName` | string | The resource group the virtual network peering was deployed into. | +| `resourceId` | string | The resource ID of the virtual network peering. | + +## Cross-referenced modules + +_None_ diff --git a/avm/res/network/virtual-network/virtual-network-peering/main.bicep b/avm/res/network/virtual-network/virtual-network-peering/main.bicep new file mode 100644 index 0000000000..0c66acd553 --- /dev/null +++ b/avm/res/network/virtual-network/virtual-network-peering/main.bicep @@ -0,0 +1,55 @@ +metadata name = 'Virtual Network Peerings' +metadata description = 'This module deploys a Virtual Network Peering.' +metadata owner = 'Azure/module-maintainers' + +@description('Optional. The Name of Vnet Peering resource. If not provided, default value will be localVnetName-remoteVnetName.') +param name string = '${localVnetName}-${last(split(remoteVirtualNetworkId, '/'))}' + +@description('Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment.') +param localVnetName string + +@description('Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID.') +param remoteVirtualNetworkId string + +@description('Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true.') +param allowForwardedTraffic bool = true + +@description('Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false.') +param allowGatewayTransit bool = false + +@description('Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true.') +param allowVirtualNetworkAccess bool = true + +@description('Optional. If we need to verify the provisioning state of the remote gateway. Default is true.') +param doNotVerifyRemoteGateways bool = true + +@description('Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false.') +param useRemoteGateways bool = false + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' existing = { + name: localVnetName +} + +resource virtualNetworkPeering 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2023-04-01' = { + name: name + parent: virtualNetwork + properties: { + allowForwardedTraffic: allowForwardedTraffic + allowGatewayTransit: allowGatewayTransit + allowVirtualNetworkAccess: allowVirtualNetworkAccess + doNotVerifyRemoteGateways: doNotVerifyRemoteGateways + useRemoteGateways: useRemoteGateways + remoteVirtualNetwork: { + id: remoteVirtualNetworkId + } + } +} + +@description('The resource group the virtual network peering was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the virtual network peering.') +output name string = virtualNetworkPeering.name + +@description('The resource ID of the virtual network peering.') +output resourceId string = virtualNetworkPeering.id diff --git a/avm/res/network/virtual-network/virtual-network-peering/main.json b/avm/res/network/virtual-network/virtual-network-peering/main.json new file mode 100644 index 0000000000..f2db8a3018 --- /dev/null +++ b/avm/res/network/virtual-network/virtual-network-peering/main.json @@ -0,0 +1,110 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.21.1.54444", + "templateHash": "10220824930947117349" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "metadata": { + "description": "Optional. The Name of Vnet Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } +} \ No newline at end of file From 83fde1a23ac4833379d43ed7a70ee863ff66afa2 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Mon, 27 Nov 2023 23:38:06 +0100 Subject: [PATCH 07/22] feat: Further improved runtime of utilities (#618) ## Description 1. Improved runtime of Set-ModuleReadMe utility by building all test files per modules using a thread each. Impact: > Runtime of test runs ***before*** change on module 'Cognitive Services' > 1. 20 s > 2. 17 s > 3. 18 s > 4. 17 s > 5. 17 s >
> > Runtime of test runs ***after*** change on module 'Cognitive Services' > 1. 11 s > 2. 9 s > 3. 9 s > 4. 10 s > 5. 10 s | Pipeline | | - | | [![avm.res.key-vault.vault](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2FreadMeSpeadup&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) | --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .../pipelines/sharedScripts/Set-ModuleReadMe.ps1 | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 index b8c7b78328..d253e6f428 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 @@ -1182,6 +1182,18 @@ function Set-UsageExamplesSection { ############################ ## Process test files ## ############################ + + # Prepare data (using thread-safe multithreading) to consume later + $buildTestFileMap = [System.Collections.Concurrent.ConcurrentDictionary[string, object]]::new() + $testFilePaths | ForEach-Object -Parallel { + $folderName = Split-Path (Split-Path -Path $_) -Leaf + $buildTemplate = bicep build $_ --stdout | ConvertFrom-Json -AsHashtable + + $dict = $using:buildTestFileMap + $null = $dict.TryAdd($folderName, $buildTemplate) + } + + # Process data $pathIndex = 1 $usageExampleSectionHeaders = @() $testFilesContent = @() @@ -1189,7 +1201,8 @@ function Set-UsageExamplesSection { # Read content $rawContentArray = Get-Content -Path $testFilePath - $compiledTestFileContent = bicep build $testFilePath --stdout | ConvertFrom-Json -AsHashtable + $folderName = Split-Path (Split-Path -Path $testFilePath) -Leaf + $compiledTestFileContent = $buildTestFileMap[$folderName] $rawContent = Get-Content -Path $testFilePath -Encoding 'utf8' | Out-String # Format example header From 69fb50d0b779a4dc1bd88fcf3eada76ad2abe5f2 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Tue, 28 Nov 2023 01:29:40 +0100 Subject: [PATCH 08/22] feat: Added test for [ORPHANED.md} files (#674) ## Description - Added test for [ORPHANED.md] files - Removed/added excess/missing files | Pipeline | | - | | [![avm.res.batch.batch-account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.batch.batch-account.yml/badge.svg?branch=users%2Falsehr%2Forphened&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.batch.batch-account.yml) | | [![avm.res.sql.server](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml/badge.svg?branch=users%2Falsehr%2Forphened&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml) | | [![avm.res.key-vault.vault](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2Forphened&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) | | [![avm.res.resource-graph.query](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.resource-graph.query.yml/badge.svg?branch=users%2Falsehr%2Forphened&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.resource-graph.query.yml) | --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/batch/batch-account/README.md | 5 -- .../cognitive-services/account/ORPHANED.md | 4 -- avm/res/cognitive-services/account/README.md | 5 -- avm/res/resource-graph/query/ORPHANED.md | 4 -- avm/res/resource-graph/query/README.md | 5 -- .../batch-account => sql/server}/ORPHANED.md | 0 avm/res/sql/server/README.md | 5 ++ .../compliance/module.tests.ps1 | 48 ++++++++++++++++++- 8 files changed, 51 insertions(+), 25 deletions(-) delete mode 100644 avm/res/cognitive-services/account/ORPHANED.md delete mode 100644 avm/res/resource-graph/query/ORPHANED.md rename avm/res/{batch/batch-account => sql/server}/ORPHANED.md (100%) diff --git a/avm/res/batch/batch-account/README.md b/avm/res/batch/batch-account/README.md index 99ce6f78cd..5c5f32c55f 100644 --- a/avm/res/batch/batch-account/README.md +++ b/avm/res/batch/batch-account/README.md @@ -1,10 +1,5 @@ # Batch Accounts `[Microsoft.Batch/batchAccounts]` -> ⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ -> -> - Only security and bug fixes are being handled by the AVM core team at present. -> - If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! - This module deploys a Batch Account. ## Navigation diff --git a/avm/res/cognitive-services/account/ORPHANED.md b/avm/res/cognitive-services/account/ORPHANED.md deleted file mode 100644 index ef8fa911d2..0000000000 --- a/avm/res/cognitive-services/account/ORPHANED.md +++ /dev/null @@ -1,4 +0,0 @@ -⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ - -- Only security and bug fixes are being handled by the AVM core team at present. -- If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! \ No newline at end of file diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index 5991ef3fba..b63f01ca87 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -1,10 +1,5 @@ # Cognitive Services `[Microsoft.CognitiveServices/accounts]` -> ⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ -> -> - Only security and bug fixes are being handled by the AVM core team at present. -> - If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! - This module deploys a Cognitive Service. ## Navigation diff --git a/avm/res/resource-graph/query/ORPHANED.md b/avm/res/resource-graph/query/ORPHANED.md deleted file mode 100644 index d76e7e1e4e..0000000000 --- a/avm/res/resource-graph/query/ORPHANED.md +++ /dev/null @@ -1,4 +0,0 @@ -⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ - -- Only security and bug fixes are being handled by the AVM core team at present. -- If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! diff --git a/avm/res/resource-graph/query/README.md b/avm/res/resource-graph/query/README.md index f8ecdbe049..e640440871 100644 --- a/avm/res/resource-graph/query/README.md +++ b/avm/res/resource-graph/query/README.md @@ -1,10 +1,5 @@ # Resource Graph Queries `[Microsoft.ResourceGraph/queries]` -> ⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ -> -> - Only security and bug fixes are being handled by the AVM core team at present. -> - If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! - This module deploys a Resource Graph Query. ## Navigation diff --git a/avm/res/batch/batch-account/ORPHANED.md b/avm/res/sql/server/ORPHANED.md similarity index 100% rename from avm/res/batch/batch-account/ORPHANED.md rename to avm/res/sql/server/ORPHANED.md diff --git a/avm/res/sql/server/README.md b/avm/res/sql/server/README.md index 60c7c09863..6136d9ae44 100644 --- a/avm/res/sql/server/README.md +++ b/avm/res/sql/server/README.md @@ -1,5 +1,10 @@ # Azure SQL Servers `[Microsoft.Sql/servers]` +> ⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ +> +> - Only security and bug fixes are being handled by the AVM core team at present. +> - If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! + This module deploys an Azure SQL Server. ## Navigation diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index e6860cb5dc..a7bb93b160 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -77,6 +77,50 @@ Describe 'File/folder tests' -Tag 'Modules' { $file = Get-Item -Path $readMeFilePath $file.Name | Should -BeExactly 'README.md' } + + It '[] Module should contain a [` ORPHANED.md `] file only if orphaned.' -TestCases ($moduleFolderTestCases | Where-Object { $_.isTopLevelModule }) { + + param( + [string] $moduleFolderPath + ) + + $templateFilePath = Join-Path -Path $moduleFolderPath 'main.bicep' + + # Use correct telemetry link based on file path + $telemetryCsvLink = $moduleFolderPath -match '[\\|\/]res[\\|\/]' ? $telemetryResCsvLink : $telemetryPtnCsvLink + + # Fetch CSV + # ========= + try { + $rawData = Invoke-WebRequest -Uri $telemetryCsvLink + } catch { + $errorMessage = "Failed to download telemetry CSV file from [$telemetryCsvLink] due to [{0}]." -f $_.Exception.Message + Write-Error $errorMessage + Set-ItResult -Skipped -Because $errorMessage + } + $csvData = $rawData.Content | ConvertFrom-Csv -Delimiter ',' + + $moduleName = Get-BRMRepositoryName -TemplateFilePath $templateFilePath + $relevantCSVRow = $csvData | Where-Object { + $_.ModuleName -eq $moduleName + } + + if (-not $relevantCSVRow) { + $errorMessage = "Failed to identify module [$moduleName]." + Write-Error $errorMessage + Set-ItResult -Skipped -Because $errorMessage + } + $isOrphaned = [String]::IsNullOrEmpty($relevantCSVRow.PrimaryModuleOwnerGHHandle) + + $orphanedFilePath = Join-Path -Path $moduleFolderPath 'ORPHANED.md' + if ($isOrphaned) { + $pathExisting = Test-Path $orphanedFilePath + $pathExisting | Should -Be $true -Because 'The module is orphaned.' + } else { + $pathExisting = Test-Path $orphanedFilePath + $pathExisting | Should -Be $false -Because ('The module is not orphaned but owned by [{0}].' -f $relevantCSVRow.PrimaryModuleOwnerGHHandle) + } + } } Context 'Top level module folder tests' { @@ -607,7 +651,7 @@ Describe 'Module tests' -Tag 'Module' { $rawData = Invoke-WebRequest -Uri $telemetryCsvLink } catch { $errorMessage = "Failed to download telemetry CSV file from [$telemetryCsvLink] due to [{0}]." -f $_.Exception.Message - Write-Error "Failed to download telemetry CSV file from [$errorMessage]." + Write-Error $errorMessage Set-ItResult -Skipped -Because $errorMessage } $csvData = $rawData.Content | ConvertFrom-Csv -Delimiter ',' @@ -621,7 +665,7 @@ Describe 'Module tests' -Tag 'Module' { if (-not $relevantCSVRow) { $errorMessage = "Failed to identify module [$moduleName]." - Write-Error "Failed to download telemetry CSV file from [$errorMessage]." + Write-Error $errorMessage Set-ItResult -Skipped -Because $errorMessage } $expectedTelemetryIdentifier = $relevantCSVRow.TelemetryIdPrefix From 67fdd510a7a0729faaf7f2b5d1047ac4524f8882 Mon Sep 17 00:00:00 2001 From: Erika Gressi <56914614+eriqua@users.noreply.github.com> Date: Tue, 28 Nov 2023 02:45:31 +0100 Subject: [PATCH 09/22] chore: CODEOWNERS update for AVM (#676) ## Description Uncomment relevant lines to allow corresponding AVM modules to be owned by module owners --- .github/CODEOWNERS | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6282e877fd..f3d52ea1a2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -17,7 +17,7 @@ #/avm/res/authorization/role-assignment/ @Azure/avm-res-authorization-roleassignment-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/authorization/role-definition/ @Azure/avm-res-authorization-roledefinition-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/automation/automation-account/ @Azure/avm-res-automation-automationaccount-module-owners-bicep @Azure/avm-core-team-technical-bicep -#/avm/res/batch/batch-account/ @Azure/avm-res-batch-batchaccount-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/res/batch/batch-account/ @Azure/avm-res-batch-batchaccount-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/cache/redis/ @Azure/avm-res-cache-redis-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/cdn/profile/ @Azure/avm-res-cdn-profile-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/cognitive-services/account/ @Azure/avm-res-cognitiveservices-account-module-owners-bicep @Azure/avm-core-team-technical-bicep @@ -49,8 +49,8 @@ #/avm/res/digital-twins/digital-twins-instance/ @Azure/avm-res-digitaltwins-digitaltwinsinstance-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/document-db/database-account/ @Azure/avm-res-documentdb-databaseaccount-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/event-grid/domain/ @Azure/avm-res-eventgrid-domain-module-owners-bicep @Azure/avm-core-team-technical-bicep -#/avm/res/event-grid/system-topic/ @Azure/avm-res-eventgrid-systemtopic-module-owners-bicep @Azure/avm-core-team-technical-bicep -#/avm/res/event-grid/topic/ @Azure/avm-res-eventgrid-topic-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/res/event-grid/system-topic/ @Azure/avm-res-eventgrid-systemtopic-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/res/event-grid/topic/ @Azure/avm-res-eventgrid-topic-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/event-hub/namespace/ @Azure/avm-res-eventhub-namespace-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/health-bot/health-bot/ @Azure/avm-res-healthbot-healthbot-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/healthcare-apis/workspace/ @Azure/avm-res-healthcareapis-workspace-module-owners-bicep @Azure/avm-core-team-technical-bicep @@ -85,8 +85,8 @@ /avm/res/network/dns-forwarding-ruleset/ @Azure/avm-res-network-dnsforwardingruleset-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/network/dns-resolver/ @Azure/avm-res-network-dnsresolver-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/network/dns-zone/ @Azure/avm-res-network-dnszone-module-owners-bicep @Azure/avm-core-team-technical-bicep -#/avm/res/network/express-route-circuit/ @Azure/avm-res-network-expressroutecircuit-module-owners-bicep @Azure/avm-core-team-technical-bicep -#/avm/res/network/express-route-gateway/ @Azure/avm-res-network-expressroutegateway-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/res/network/express-route-circuit/ @Azure/avm-res-network-expressroutecircuit-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/res/network/express-route-gateway/ @Azure/avm-res-network-expressroutegateway-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/network/firewall-policy/ @Azure/avm-res-network-firewallpolicy-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/network/front-door/ @Azure/avm-res-network-frontdoor-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/network/front-door-web-application-firewall-policy/ @Azure/avm-res-network-frontdoorwebapplicationfirewallpolicy-module-owners-bicep @Azure/avm-core-team-technical-bicep @@ -107,7 +107,7 @@ #/avm/res/network/service-endpoint-policy/ @Azure/avm-res-network-serviceendpointpolicy-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/network/trafficmanagerprofile/ @Azure/avm-res-network-trafficmanagerprofile-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/network/virtual-hub/ @Azure/avm-res-network-virtualhub-module-owners-bicep @Azure/avm-core-team-technical-bicep -#/avm/res/network/virtual-network/ @Azure/avm-res-network-virtualnetwork-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/res/network/virtual-network/ @Azure/avm-res-network-virtualnetwork-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/network/virtual-network-gateway/ @Azure/avm-res-network-virtualnetworkgateway-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/network/virtual-wan/ @Azure/avm-res-network-virtualwan-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/network/vpn-gateway/ @Azure/avm-res-network-vpngateway-module-owners-bicep @Azure/avm-core-team-technical-bicep @@ -119,7 +119,7 @@ #/avm/res/purview/account/ @Azure/avm-res-purview-account-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/recovery-services/vault/ @Azure/avm-res-recoveryservices-vault-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/relay/namespace/ @Azure/avm-res-relay-namespace-module-owners-bicep @Azure/avm-core-team-technical-bicep -#/avm/res/resource-graph/query/ @Azure/avm-res-resourcegraph-query-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/res/resource-graph/query/ @Azure/avm-res-resourcegraph-query-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/resources/deployment-script/ @Azure/avm-res-resources-deploymentscript-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/resources/resource-group/ @Azure/avm-res-resources-resourcegroup-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/resources/tags/ @Azure/avm-res-resources-tags-module-owners-bicep @Azure/avm-core-team-technical-bicep From 85dc82c47a993ce6669398d232b923f45a266ec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Gr=C3=A4f?= Date: Tue, 28 Nov 2023 19:17:24 +1000 Subject: [PATCH 10/22] fix: avm/res/network/private-endpoint (#656) ## Description fix for https://github.com/Azure/bicep-registry-modules/issues/607 [![avm.res.network.private-endpoint](https://github.com/segraef/bicep-registry-modules/actions/workflows/avm.res.network.private-endpoint.yml/badge.svg?branch=feature%2Favm.res.network.privateendpoint)](https://github.com/segraef/bicep-registry-modules/actions/workflows/avm.res.network.private-endpoint.yml) --------- Co-authored-by: Alexander Sehr Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/network/private-endpoint/README.md | 315 +++++++++++++----- avm/res/network/private-endpoint/main.bicep | 58 +++- avm/res/network/private-endpoint/main.json | 117 +++++-- .../tests/e2e/defaults/main.test.bicep | 27 +- .../tests/e2e/max/main.test.bicep | 19 +- .../tests/e2e/waf-aligned/main.test.bicep | 37 +- avm/res/network/private-endpoint/version.json | 4 +- 7 files changed, 423 insertions(+), 154 deletions(-) diff --git a/avm/res/network/private-endpoint/README.md b/avm/res/network/private-endpoint/README.md index ba9d6f73c0..57fb00ab07 100644 --- a/avm/res/network/private-endpoint/README.md +++ b/avm/res/network/private-endpoint/README.md @@ -47,14 +47,32 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = name: '${uniqueString(deployment().name, location)}-test-npemin' params: { // Required parameters - groupIds: [ - 'vault' - ] name: 'npemin001' - serviceResourceId: '' subnetResourceId: '' // Non-required parameters + applicationSecurityGroupResourceIds: [] + customDnsConfigs: [] + customNetworkInterfaceName: '' + ipConfigurations: [] location: '' + lock: {} + manualPrivateLinkServiceConnections: [] + privateDnsZoneGroupName: '' + privateDnsZoneResourceIds: [] + privateLinkServiceConnections: [ + { + name: 'npemin001' + properties: { + groupIds: [ + 'vault' + ] + privateLinkServiceId: '' + requestMessage: '' + } + } + ] + roleAssignments: [] + tags: {} } } ``` @@ -72,23 +90,59 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "contentVersion": "1.0.0.0", "parameters": { // Required parameters - "groupIds": { - "value": [ - "vault" - ] - }, "name": { "value": "npemin001" }, - "serviceResourceId": { - "value": "" - }, "subnetResourceId": { "value": "" }, // Non-required parameters + "applicationSecurityGroupResourceIds": { + "value": [] + }, + "customDnsConfigs": { + "value": [] + }, + "customNetworkInterfaceName": { + "value": "" + }, + "ipConfigurations": { + "value": [] + }, "location": { "value": "" + }, + "lock": { + "value": {} + }, + "manualPrivateLinkServiceConnections": { + "value": [] + }, + "privateDnsZoneGroupName": { + "value": "" + }, + "privateDnsZoneResourceIds": { + "value": [] + }, + "privateLinkServiceConnections": { + "value": [ + { + "name": "npemin001", + "properties": { + "groupIds": [ + "vault" + ], + "privateLinkServiceId": "", + "requestMessage": "" + } + } + ] + }, + "roleAssignments": { + "value": [] + }, + "tags": { + "value": {} } } } @@ -111,11 +165,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = name: '${uniqueString(deployment().name, location)}-test-npemax' params: { // Required parameters - groupIds: [ - 'vault' - ] name: 'npemax001' - serviceResourceId: '' subnetResourceId: '' // Non-required parameters applicationSecurityGroupResourceIds: [ @@ -145,9 +195,23 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = kind: 'CanNotDelete' name: 'myCustomLockName' } + manualPrivateLinkServiceConnections: [] + privateDnsZoneGroupName: 'default' privateDnsZoneResourceIds: [ '' ] + privateLinkServiceConnections: [ + { + name: 'npemax001' + properties: { + groupIds: [ + 'vault' + ] + privateLinkServiceId: '' + requestMessage: '' + } + } + ] roleAssignments: [ { principalId: '' @@ -187,17 +251,9 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "contentVersion": "1.0.0.0", "parameters": { // Required parameters - "groupIds": { - "value": [ - "vault" - ] - }, "name": { "value": "npemax001" }, - "serviceResourceId": { - "value": "" - }, "subnetResourceId": { "value": "" }, @@ -241,11 +297,31 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "name": "myCustomLockName" } }, + "manualPrivateLinkServiceConnections": { + "value": [] + }, + "privateDnsZoneGroupName": { + "value": "default" + }, "privateDnsZoneResourceIds": { "value": [ "" ] }, + "privateLinkServiceConnections": { + "value": [ + { + "name": "npemax001", + "properties": { + "groupIds": [ + "vault" + ], + "privateLinkServiceId": "", + "requestMessage": "" + } + } + ] + }, "roleAssignments": { "value": [ { @@ -293,16 +369,13 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = name: '${uniqueString(deployment().name, location)}-test-npewaf' params: { // Required parameters - groupIds: [ - 'vault' - ] name: 'npewaf001' - serviceResourceId: '' subnetResourceId: '' // Non-required parameters applicationSecurityGroupResourceIds: [ '' ] + customDnsConfigs: [] customNetworkInterfaceName: 'npewaf001nic' ipConfigurations: [ { @@ -319,24 +392,21 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = kind: 'CanNotDelete' name: 'myCustomLockName' } + manualPrivateLinkServiceConnections: [] + privateDnsZoneGroupName: 'default' privateDnsZoneResourceIds: [ '' ] - roleAssignments: [ - { - principalId: '' - principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Owner' - } - { - principalId: '' - principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' - } + privateLinkServiceConnections: [ { - principalId: '' - principalType: 'ServicePrincipal' - roleDefinitionIdOrName: '' + name: 'npewaf001' + properties: { + groupIds: [ + 'vault' + ] + privateLinkServiceId: '' + requestMessage: '' + } } ] tags: { @@ -361,17 +431,9 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "contentVersion": "1.0.0.0", "parameters": { // Required parameters - "groupIds": { - "value": [ - "vault" - ] - }, "name": { "value": "npewaf001" }, - "serviceResourceId": { - "value": "" - }, "subnetResourceId": { "value": "" }, @@ -381,6 +443,9 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "" ] }, + "customDnsConfigs": { + "value": [] + }, "customNetworkInterfaceName": { "value": "npewaf001nic" }, @@ -405,27 +470,28 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "name": "myCustomLockName" } }, + "manualPrivateLinkServiceConnections": { + "value": [] + }, + "privateDnsZoneGroupName": { + "value": "default" + }, "privateDnsZoneResourceIds": { "value": [ "" ] }, - "roleAssignments": { + "privateLinkServiceConnections": { "value": [ { - "principalId": "", - "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Owner" - }, - { - "principalId": "", - "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" - }, - { - "principalId": "", - "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "" + "name": "npewaf001", + "properties": { + "groupIds": [ + "vault" + ], + "privateLinkServiceId": "", + "requestMessage": "" + } } ] }, @@ -450,9 +516,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = | Parameter | Type | Description | | :-- | :-- | :-- | -| [`groupIds`](#parameter-groupids) | array | Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to. | | [`name`](#parameter-name) | string | Name of the private endpoint resource to create. | -| [`serviceResourceId`](#parameter-serviceresourceid) | string | Resource ID of the resource that needs to be connected to the network. | | [`subnetResourceId`](#parameter-subnetresourceid) | string | Resource ID of the subnet where the endpoint needs to be created. | **Optional parameters** @@ -466,9 +530,10 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = | [`ipConfigurations`](#parameter-ipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | | [`location`](#parameter-location) | string | Location for all Resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | -| [`manualPrivateLinkServiceConnections`](#parameter-manualprivatelinkserviceconnections) | array | Manual PrivateLink Service Connections. | +| [`manualPrivateLinkServiceConnections`](#parameter-manualprivatelinkserviceconnections) | array | A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. | | [`privateDnsZoneGroupName`](#parameter-privatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnections`](#parameter-privatelinkserviceconnections) | array | A grouping of information about the connection to the remote resource. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`tags`](#parameter-tags) | object | Tags to be applied on all resources/resource groups in this deployment. | @@ -517,12 +582,6 @@ Enable/Disable usage telemetry for module. - Type: bool - Default: `True` -### Parameter: `groupIds` - -Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to. -- Required: Yes -- Type: array - ### Parameter: `ipConfigurations` A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. @@ -613,10 +672,58 @@ Optional. Specify the name of lock. ### Parameter: `manualPrivateLinkServiceConnections` -Manual PrivateLink Service Connections. +A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. - Required: No - Type: array + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`name`](#parameter-manualprivatelinkserviceconnectionsname) | Yes | string | Required. The name of the private link service connection. | +| [`properties`](#parameter-manualprivatelinkserviceconnectionsproperties) | Yes | object | Required. Properties of private link service connection. | + +### Parameter: `manualPrivateLinkServiceConnections.name` + +Required. The name of the private link service connection. + +- Required: Yes +- Type: string + +### Parameter: `manualPrivateLinkServiceConnections.properties` + +Required. Properties of private link service connection. + +- Required: Yes +- Type: object + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`groupIds`](#parameter-manualprivatelinkserviceconnectionspropertiesgroupids) | Yes | array | Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. | +| [`privateLinkServiceId`](#parameter-manualprivatelinkserviceconnectionspropertiesprivatelinkserviceid) | Yes | string | Required. The resource id of private link service. | +| [`requestMessage`](#parameter-manualprivatelinkserviceconnectionspropertiesrequestmessage) | Yes | string | Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars. | + +### Parameter: `manualPrivateLinkServiceConnections.properties.groupIds` + +Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: array + +### Parameter: `manualPrivateLinkServiceConnections.properties.privateLinkServiceId` + +Required. The resource id of private link service. + +- Required: Yes +- Type: string + +### Parameter: `manualPrivateLinkServiceConnections.properties.requestMessage` + +Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars. + +- Required: Yes +- Type: string + + ### Parameter: `name` Name of the private endpoint resource to create. @@ -635,6 +742,60 @@ The private DNS zone groups to associate the private endpoint. A DNS zone group - Required: No - Type: array +### Parameter: `privateLinkServiceConnections` + +A grouping of information about the connection to the remote resource. +- Required: No +- Type: array + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`name`](#parameter-privatelinkserviceconnectionsname) | Yes | string | Required. The name of the private link service connection. | +| [`properties`](#parameter-privatelinkserviceconnectionsproperties) | Yes | object | Required. Properties of private link service connection. | + +### Parameter: `privateLinkServiceConnections.name` + +Required. The name of the private link service connection. + +- Required: Yes +- Type: string + +### Parameter: `privateLinkServiceConnections.properties` + +Required. Properties of private link service connection. + +- Required: Yes +- Type: object + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`groupIds`](#parameter-privatelinkserviceconnectionspropertiesgroupids) | Yes | array | Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. | +| [`privateLinkServiceId`](#parameter-privatelinkserviceconnectionspropertiesprivatelinkserviceid) | Yes | string | Required. The resource id of private link service. | +| [`requestMessage`](#parameter-privatelinkserviceconnectionspropertiesrequestmessage) | Yes | string | Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars. | + +### Parameter: `privateLinkServiceConnections.properties.groupIds` + +Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: array + +### Parameter: `privateLinkServiceConnections.properties.privateLinkServiceId` + +Required. The resource id of private link service. + +- Required: Yes +- Type: string + +### Parameter: `privateLinkServiceConnections.properties.requestMessage` + +Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars. + +- Required: Yes +- Type: string + + ### Parameter: `roleAssignments` Array of role assignments to create. @@ -703,12 +864,6 @@ Required. The role to assign. You can provide either the display name of the rol - Required: Yes - Type: string -### Parameter: `serviceResourceId` - -Resource ID of the resource that needs to be connected to the network. -- Required: Yes -- Type: string - ### Parameter: `subnetResourceId` Resource ID of the subnet where the endpoint needs to be created. diff --git a/avm/res/network/private-endpoint/main.bicep b/avm/res/network/private-endpoint/main.bicep index 753c62d02a..8ac95a1afa 100644 --- a/avm/res/network/private-endpoint/main.bicep +++ b/avm/res/network/private-endpoint/main.bicep @@ -8,9 +8,6 @@ param name string @description('Required. Resource ID of the subnet where the endpoint needs to be created.') param subnetResourceId string -@description('Required. Resource ID of the resource that needs to be connected to the network.') -param serviceResourceId string - @description('Optional. Application security groups in which the private endpoint IP configuration is included.') param applicationSecurityGroupResourceIds array? @@ -20,9 +17,6 @@ param customNetworkInterfaceName string? @description('Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints.') param ipConfigurations ipConfigurationsType -@description('Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to.') -param groupIds array - @description('Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided.') param privateDnsZoneGroupName string? @@ -44,8 +38,11 @@ param tags object? @description('Optional. Custom DNS configurations.') param customDnsConfigs customDnsConfigType -@description('Optional. Manual PrivateLink Service Connections.') -param manualPrivateLinkServiceConnections array? +@description('Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource.') +param manualPrivateLinkServiceConnections manualPrivateLinkServiceConnectionsType + +@description('Optional. A grouping of information about the connection to the remote resource.') +param privateLinkServiceConnections privateLinkServiceConnectionsType @description('Optional. Enable/Disable usage telemetry for module.') param enableTelemetry bool = true @@ -93,19 +90,10 @@ resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-04-01' = { customNetworkInterfaceName: customNetworkInterfaceName ?? '' ipConfigurations: ipConfigurations ?? [] manualPrivateLinkServiceConnections: manualPrivateLinkServiceConnections ?? [] - privateLinkServiceConnections: [ - { - name: name - properties: { - privateLinkServiceId: serviceResourceId - groupIds: groupIds - } - } - ] + privateLinkServiceConnections: privateLinkServiceConnections ?? [] subnet: { id: subnetResourceId } - } } @@ -205,6 +193,40 @@ type ipConfigurationsType = { } }[]? +type manualPrivateLinkServiceConnectionsType = { + @description('Required. The name of the private link service connection.') + name: string + + @description('Required. Properties of private link service connection.') + properties: { + @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to.') + groupIds: array + + @description('Required. The resource id of private link service.') + privateLinkServiceId: string + + @description('Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars.') + requestMessage: string + } +}[]? + +type privateLinkServiceConnectionsType = { + @description('Required. The name of the private link service connection.') + name: string + + @description('Required. Properties of private link service connection.') + properties: { + @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to.') + groupIds: array + + @description('Required. The resource id of private link service.') + privateLinkServiceId: string + + @description('Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars.') + requestMessage: string + } +}[]? + type customDnsConfigType = { @description('Required. Fqdn that resolves to private endpoint ip address.') fqdn: string diff --git a/avm/res/network/private-endpoint/main.json b/avm/res/network/private-endpoint/main.json index 0b1a203f91..03db08f0e0 100644 --- a/avm/res/network/private-endpoint/main.json +++ b/avm/res/network/private-endpoint/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "11574872241175195302" + "templateHash": "9677328568170167813" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -145,6 +145,88 @@ }, "nullable": true }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, "customDnsConfigType": { "type": "array", "items": { @@ -183,12 +265,6 @@ "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "serviceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource that needs to be connected to the network." - } - }, "applicationSecurityGroupResourceIds": { "type": "array", "nullable": true, @@ -209,12 +285,6 @@ "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." } }, - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." - } - }, "privateDnsZoneGroupName": { "type": "string", "nullable": true, @@ -262,10 +332,15 @@ } }, "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." + "description": "Optional. A grouping of information about the connection to the remote resource." } }, "enableTelemetry": { @@ -331,15 +406,7 @@ "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": [ - { - "name": "[parameters('name')]", - "properties": { - "privateLinkServiceId": "[parameters('serviceResourceId')]", - "groupIds": "[parameters('groupIds')]" - } - } - ], + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", "subnet": { "id": "[parameters('subnetResourceId')]" } diff --git a/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep b/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep index 69d2fc7a25..010b0ad29c 100644 --- a/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep @@ -55,10 +55,29 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' params: { name: '${namePrefix}${serviceShort}001' location: location - groupIds: [ - 'vault' - ] - serviceResourceId: nestedDependencies.outputs.keyVaultResourceId subnetResourceId: nestedDependencies.outputs.subnetResourceId + // Workaround for PSRule + lock: {} + roleAssignments: [] + applicationSecurityGroupResourceIds: [] + customNetworkInterfaceName: '' + privateDnsZoneGroupName: '' + ipConfigurations: [] + customDnsConfigs: [] + privateDnsZoneResourceIds: [] + manualPrivateLinkServiceConnections: [] + privateLinkServiceConnections: [ + { + name: '${namePrefix}${serviceShort}001' + properties: { + privateLinkServiceId: nestedDependencies.outputs.keyVaultResourceId + groupIds: [ + 'vault' + ] + requestMessage: '' + } + } + ] + tags: {} } }] diff --git a/avm/res/network/private-endpoint/tests/e2e/max/main.test.bicep b/avm/res/network/private-endpoint/tests/e2e/max/main.test.bicep index 5f9f625cfa..65339afdbc 100644 --- a/avm/res/network/private-endpoint/tests/e2e/max/main.test.bicep +++ b/avm/res/network/private-endpoint/tests/e2e/max/main.test.bicep @@ -54,10 +54,6 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' params: { name: '${namePrefix}${serviceShort}001' location: location - groupIds: [ - 'vault' - ] - serviceResourceId: nestedDependencies.outputs.keyVaultResourceId subnetResourceId: nestedDependencies.outputs.subnetResourceId lock: { kind: 'CanNotDelete' @@ -110,5 +106,20 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Environment: 'Non-Prod' Role: 'DeploymentValidation' } + // Workaround for PSRule + privateDnsZoneGroupName: 'default' + manualPrivateLinkServiceConnections: [] + privateLinkServiceConnections: [ + { + name: '${namePrefix}${serviceShort}001' + properties: { + privateLinkServiceId: nestedDependencies.outputs.keyVaultResourceId + groupIds: [ + 'vault' + ] + requestMessage: '' + } + } + ] } }] diff --git a/avm/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep index e8c7fb5e3b..b087066712 100644 --- a/avm/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep @@ -54,10 +54,6 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' params: { name: '${namePrefix}${serviceShort}001' location: location - groupIds: [ - 'vault' - ] - serviceResourceId: nestedDependencies.outputs.keyVaultResourceId subnetResourceId: nestedDependencies.outputs.subnetResourceId lock: { kind: 'CanNotDelete' @@ -66,23 +62,6 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' privateDnsZoneResourceIds: [ nestedDependencies.outputs.privateDNSZoneResourceId ] - roleAssignments: [ - { - roleDefinitionIdOrName: 'Owner' - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' - } - ] ipConfigurations: [ { name: 'myIPconfig' @@ -102,5 +81,21 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Environment: 'Non-Prod' Role: 'DeploymentValidation' } + // Workaround for PSRule + privateDnsZoneGroupName: 'default' + customDnsConfigs: [] + manualPrivateLinkServiceConnections: [] + privateLinkServiceConnections: [ + { + name: '${namePrefix}${serviceShort}001' + properties: { + privateLinkServiceId: nestedDependencies.outputs.keyVaultResourceId + groupIds: [ + 'vault' + ] + requestMessage: '' + } + } + ] } }] diff --git a/avm/res/network/private-endpoint/version.json b/avm/res/network/private-endpoint/version.json index 1c035df49f..b3d560b1ad 100644 --- a/avm/res/network/private-endpoint/version.json +++ b/avm/res/network/private-endpoint/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.2", + "version": "0.3", "pathFilters": [ "./main.json" ] -} \ No newline at end of file +} From 7c45910fc686688ccd181ba282305b6804889e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Gr=C3=A4f?= Date: Tue, 28 Nov 2023 19:21:39 +1000 Subject: [PATCH 11/22] feat: avm/res/network/route-table (#655) [![avm.res.network.route-table](https://github.com/segraef/bicep-registry-modules/actions/workflows/avm.res.network.route-table.yml/badge.svg?branch=feature%2Froutetable)](https://github.com/segraef/bicep-registry-modules/actions/workflows/avm.res.network.route-table.yml) --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> Co-authored-by: Alexander Sehr --- .github/CODEOWNERS | 2 +- .../workflows/avm.res.network.route-table.yml | 81 +++ avm/res/network/route-table/README.md | 469 ++++++++++++++++++ avm/res/network/route-table/main.bicep | 134 +++++ avm/res/network/route-table/main.json | 272 ++++++++++ .../tests/e2e/defaults/main.test.bicep | 45 ++ .../tests/e2e/max/dependencies.bicep | 13 + .../route-table/tests/e2e/max/main.test.bicep | 90 ++++ .../tests/e2e/waf-aligned/main.test.bicep | 64 +++ avm/res/network/route-table/version.json | 7 + 10 files changed, 1176 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/avm.res.network.route-table.yml create mode 100644 avm/res/network/route-table/README.md create mode 100644 avm/res/network/route-table/main.bicep create mode 100644 avm/res/network/route-table/main.json create mode 100644 avm/res/network/route-table/tests/e2e/defaults/main.test.bicep create mode 100644 avm/res/network/route-table/tests/e2e/max/dependencies.bicep create mode 100644 avm/res/network/route-table/tests/e2e/max/main.test.bicep create mode 100644 avm/res/network/route-table/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/res/network/route-table/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f3d52ea1a2..726c670aff 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -103,7 +103,7 @@ #/avm/res/network/private-link-service/ @Azure/avm-res-network-privatelinkservice-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/network/public-ip-address/ @Azure/avm-res-network-publicipaddress-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/network/public-ip-prefix/ @Azure/avm-res-network-publicipprefix-module-owners-bicep @Azure/avm-core-team-technical-bicep -#/avm/res/network/route-table/ @Azure/avm-res-network-routetable-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/res/network/route-table/ @Azure/avm-res-network-routetable-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/network/service-endpoint-policy/ @Azure/avm-res-network-serviceendpointpolicy-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/network/trafficmanagerprofile/ @Azure/avm-res-network-trafficmanagerprofile-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/network/virtual-hub/ @Azure/avm-res-network-virtualhub-module-owners-bicep @Azure/avm-core-team-technical-bicep diff --git a/.github/workflows/avm.res.network.route-table.yml b/.github/workflows/avm.res.network.route-table.yml new file mode 100644 index 0000000000..d2614340da --- /dev/null +++ b/.github/workflows/avm.res.network.route-table.yml @@ -0,0 +1,81 @@ +name: "avm.res.network.route-table" + +on: + schedule: + - cron: "0 12 1/15 * *" # Bi-Weekly Test (on 1st & 15th of month) + 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 + + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.network.route-table.yml" + - "avm/res/network/route-table/**" + - "avm/utilities/pipelines/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/network/route-table" + workflowPath: ".github/workflows/avm.res.network.route-table.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-20.04 + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get parameter file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Module" + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/res/network/route-table/README.md b/avm/res/network/route-table/README.md new file mode 100644 index 0000000000..1c857e3d5e --- /dev/null +++ b/avm/res/network/route-table/README.md @@ -0,0 +1,469 @@ +# Route Tables `[Microsoft.Network/routeTables]` + +This module deploys a User Defined Route Table (UDR). + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| 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/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/routeTables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/routeTables) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/route-table:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module routeTable 'br/public:avm/res/network/route-table:' = { + name: '${uniqueString(deployment().name, location)}-test-nrtmin' + params: { + // Required parameters + name: 'nrtmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +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": "nrtmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module routeTable 'br/public:avm/res/network/route-table:' = { + name: '${uniqueString(deployment().name, location)}-test-nrtmax' + params: { + // Required parameters + name: 'nrtmax001' + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + routes: [ + { + name: 'default' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopIpAddress: '172.16.0.20' + nextHopType: 'VirtualAppliance' + } + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +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": "nrtmax001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "routes": { + "value": [ + { + "name": "default", + "properties": { + "addressPrefix": "0.0.0.0/0", + "nextHopIpAddress": "172.16.0.20", + "nextHopType": "VirtualAppliance" + } + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module routeTable 'br/public:avm/res/network/route-table:' = { + name: '${uniqueString(deployment().name, location)}-test-nrtwaf' + params: { + // Required parameters + name: 'nrtwaf001' + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + routes: [ + { + name: 'default' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopIpAddress: '172.16.0.20' + nextHopType: 'VirtualAppliance' + } + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +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": "nrtwaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "routes": { + "value": [ + { + "name": "default", + "properties": { + "addressPrefix": "0.0.0.0/0", + "nextHopIpAddress": "172.16.0.20", + "nextHopType": "VirtualAppliance" + } + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name given for the hub route table. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`disableBgpRoutePropagation`](#parameter-disablebgproutepropagation) | bool | Switch to disable BGP route propagation. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-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'. | +| [`routes`](#parameter-routes) | array | An Array of Routes to be established within the hub route table. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `disableBgpRoutePropagation` + +Switch to disable BGP route propagation. +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all resources. +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. +- Required: No +- Type: object + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`kind`](#parameter-lockkind) | No | string | Optional. Specify the type of lock. | +| [`name`](#parameter-lockname) | No | string | Optional. Specify the name of lock. | + +### Parameter: `lock.kind` + +Optional. Specify the type of lock. + +- Required: No +- Type: string +- Allowed: `[CanNotDelete, None, ReadOnly]` + +### Parameter: `lock.name` + +Optional. Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `name` + +Name given for the hub route table. +- Required: Yes +- Type: string + +### Parameter: `roleAssignments` + +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'. +- Required: No +- Type: array + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`condition`](#parameter-roleassignmentscondition) | No | string | 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" | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | No | string | Optional. Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | No | string | Optional. The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | +| [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | + +### Parameter: `roleAssignments.condition` + +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" + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Optional. Version of the condition. + +- Required: No +- Type: string +- Allowed: `[2.0]` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +Optional. The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +Optional. The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalId` + +Required. The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.principalType` + +Optional. The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: `[Device, ForeignGroup, Group, ServicePrincipal, User]` + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead. + +- Required: Yes +- Type: string + +### Parameter: `routes` + +An Array of Routes to be established within the hub route table. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `tags` + +Tags of the resource. +- Required: No +- Type: object + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the route table. | +| `resourceGroupName` | string | The resource group the route table was deployed into. | +| `resourceId` | string | The resource ID of the route table. | + +## Cross-referenced modules + +_None_ diff --git a/avm/res/network/route-table/main.bicep b/avm/res/network/route-table/main.bicep new file mode 100644 index 0000000000..2c596f557d --- /dev/null +++ b/avm/res/network/route-table/main.bicep @@ -0,0 +1,134 @@ +metadata name = 'Route Tables' +metadata description = 'This module deploys a User Defined Route Table (UDR).' +metadata owner = 'Azure/module-maintainers' + +@description('Required. Name given for the hub route table.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. An Array of Routes to be established within the hub route table.') +param routes array = [] + +@description('Optional. Switch to disable BGP route propagation.') +param disableBgpRoutePropagation bool = false + +@description('Optional. The lock settings of the service.') +param lock lockType + +@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 roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + '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 avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: take('46d3xbcp.res.network-routetable.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', 64) + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource routeTable 'Microsoft.Network/routeTables@2023-04-01' = { + name: name + location: location + tags: tags + properties: { + routes: routes + disableBgpRoutePropagation: disableBgpRoutePropagation + } +} + +resource routeTable_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' ? 'Cannot delete resource or child resources.' : 'Cannot delete or modify the resource or child resources.' + } + scope: routeTable +} + +resource routeTable_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { + name: guid(routeTable.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) + properties: { + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: routeTable +}] + +@description('The resource group the route table was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the route table.') +output name string = routeTable.name + +@description('The resource ID of the route table.') +output resourceId string = routeTable.id + +@description('The location the resource was deployed into.') +output location string = routeTable.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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"') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/res/network/route-table/main.json b/avm/res/network/route-table/main.json new file mode 100644 index 0000000000..8aa492459b --- /dev/null +++ b/avm/res/network/route-table/main.json @@ -0,0 +1,272 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "6317323502554535880" + }, + "name": "Route Tables", + "description": "This module deploys a User Defined Route Table (UDR).", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name given for the hub route table." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "routes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An Array of Routes to be established within the hub route table." + } + }, + "disableBgpRoutePropagation": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Switch to disable BGP route propagation." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "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'." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[take(format('46d3xbcp.res.network-routetable.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "routeTable": { + "type": "Microsoft.Network/routeTables", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "routes": "[parameters('routes')]", + "disableBgpRoutePropagation": "[parameters('disableBgpRoutePropagation')]" + } + }, + "routeTable_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/routeTables/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "routeTable" + ] + }, + "routeTable_roleAssignments": { + "copy": { + "name": "routeTable_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/routeTables/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/routeTables', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "routeTable" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the route table was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the route table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the route table." + }, + "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('routeTable', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/res/network/route-table/tests/e2e/defaults/main.test.bicep b/avm/res/network/route-table/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..8161677499 --- /dev/null +++ b/avm/res/network/route-table/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,45 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.routetables-${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 = 'nrtmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + } +} diff --git a/avm/res/network/route-table/tests/e2e/max/dependencies.bicep b/avm/res/network/route-table/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..a7f42aee7b --- /dev/null +++ b/avm/res/network/route-table/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/network/route-table/tests/e2e/max/main.test.bicep b/avm/res/network/route-table/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..f9bea9fcab --- /dev/null +++ b/avm/res/network/route-table/tests/e2e/max/main.test.bicep @@ -0,0 +1,90 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.routetables-${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 = 'nrtmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + routes: [ + { + name: 'default' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopIpAddress: '172.16.0.20' + nextHopType: 'VirtualAppliance' + } + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +} diff --git a/avm/res/network/route-table/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/route-table/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..6dc11c0803 --- /dev/null +++ b/avm/res/network/route-table/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,64 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.routetables-${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 = 'nrtwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + routes: [ + { + name: 'default' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopIpAddress: '172.16.0.20' + nextHopType: 'VirtualAppliance' + } + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +} diff --git a/avm/res/network/route-table/version.json b/avm/res/network/route-table/version.json new file mode 100644 index 0000000000..7fa401bdf7 --- /dev/null +++ b/avm/res/network/route-table/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From 0f10b10450df7657fac8e6e389e2f9a4e09d0f80 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Tue, 28 Nov 2023 19:27:46 +0100 Subject: [PATCH 12/22] fix: Hardcoded version check #669 (#675) ## Description Replaced hardcoded version check (using cognitive services) with `ModulePath` reference Closes: #669 ## Adding a new module - [ ] A proposal has been submitted and approved. - [ ] I have included "Closes #{module_proposal_issue_number}" in the PR description. - [ ] I have run `brm validate` locally to verify the module files. - [ ] I have run deployment tests locally to ensure the module is deployable. ## Updating an existing module - [x] This is a bug fix: - [x] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] I have run `brm validate` locally to verify the module files. - [ ] I have run deployment tests locally to ensure the module is deployable. - [ ] I have read the [Updating an existing module](https://github.com/Azure/bicep-registry-modules/blob/main/CONTRIBUTING.md#updating-an-existing-module) section in the contributing guide and updated the `version.json` file properly: - [ ] The PR contains backwards compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`. - [ ] The PR contains backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] The PR contains breaking changes, and I have bumped the MAJOR version in `version.json`. - [ ] I have updated the examples in README with the latest module version number. --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .github/workflows/publish-module.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-module.yml b/.github/workflows/publish-module.yml index 57f3527160..2cd04c6786 100644 --- a/.github/workflows/publish-module.yml +++ b/.github/workflows/publish-module.yml @@ -104,7 +104,7 @@ jobs: done while true; do - TAGS=https://mcr.microsoft.com/v2/bicep/ai/cognitiveservices/tags/list + TAGS=https://mcr.microsoft.com/v2/bicep/$ModulePath/tags/list echo curl -sLo tags $TAGS curl -sLo tags $TAGS echo "Tags:" From 10adf7c1b5eb997b10c4b0c865823044b977119a Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Tue, 28 Nov 2023 23:25:11 +0100 Subject: [PATCH 13/22] fix: Corrected optional PE parameter definition (#678) ## Description - Updated RequestMessage parameter to be as optional as it should be | Pipeline | | - | | [![avm.res.network.private-endpoint](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.private-endpoint.yml/badge.svg?branch=users%2Falsehr%2Fpe_Message_fix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.private-endpoint.yml) | --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/network/private-endpoint/README.md | 16 ++++++---------- avm/res/network/private-endpoint/main.bicep | 2 +- avm/res/network/private-endpoint/main.json | 3 ++- .../tests/e2e/defaults/main.test.bicep | 1 - .../tests/e2e/max/main.test.bicep | 2 +- .../tests/e2e/waf-aligned/main.test.bicep | 1 - 6 files changed, 10 insertions(+), 15 deletions(-) diff --git a/avm/res/network/private-endpoint/README.md b/avm/res/network/private-endpoint/README.md index 57fb00ab07..0015b935b3 100644 --- a/avm/res/network/private-endpoint/README.md +++ b/avm/res/network/private-endpoint/README.md @@ -67,7 +67,6 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = 'vault' ] privateLinkServiceId: '' - requestMessage: '' } } ] @@ -132,8 +131,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "groupIds": [ "vault" ], - "privateLinkServiceId": "", - "requestMessage": "" + "privateLinkServiceId": "" } } ] @@ -208,7 +206,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = 'vault' ] privateLinkServiceId: '' - requestMessage: '' + requestMessage: 'Hey there' } } ] @@ -317,7 +315,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "vault" ], "privateLinkServiceId": "", - "requestMessage": "" + "requestMessage": "Hey there" } } ] @@ -405,7 +403,6 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = 'vault' ] privateLinkServiceId: '' - requestMessage: '' } } ] @@ -489,8 +486,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "groupIds": [ "vault" ], - "privateLinkServiceId": "", - "requestMessage": "" + "privateLinkServiceId": "" } } ] @@ -772,7 +768,7 @@ Required. Properties of private link service connection. | :-- | :-- | :--| :-- | | [`groupIds`](#parameter-privatelinkserviceconnectionspropertiesgroupids) | Yes | array | Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. | | [`privateLinkServiceId`](#parameter-privatelinkserviceconnectionspropertiesprivatelinkserviceid) | Yes | string | Required. The resource id of private link service. | -| [`requestMessage`](#parameter-privatelinkserviceconnectionspropertiesrequestmessage) | Yes | string | Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars. | +| [`requestMessage`](#parameter-privatelinkserviceconnectionspropertiesrequestmessage) | No | string | Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars. | ### Parameter: `privateLinkServiceConnections.properties.groupIds` @@ -792,7 +788,7 @@ Required. The resource id of private link service. Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars. -- Required: Yes +- Required: No - Type: string diff --git a/avm/res/network/private-endpoint/main.bicep b/avm/res/network/private-endpoint/main.bicep index 8ac95a1afa..08399b166f 100644 --- a/avm/res/network/private-endpoint/main.bicep +++ b/avm/res/network/private-endpoint/main.bicep @@ -223,7 +223,7 @@ type privateLinkServiceConnectionsType = { privateLinkServiceId: string @description('Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars.') - requestMessage: string + requestMessage: string? } }[]? diff --git a/avm/res/network/private-endpoint/main.json b/avm/res/network/private-endpoint/main.json index 03db08f0e0..7caa529b5d 100644 --- a/avm/res/network/private-endpoint/main.json +++ b/avm/res/network/private-endpoint/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "9677328568170167813" + "templateHash": "2821141217598568122" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -214,6 +214,7 @@ }, "requestMessage": { "type": "string", + "nullable": true, "metadata": { "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." } diff --git a/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep b/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep index 010b0ad29c..14c6f0e2d9 100644 --- a/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep @@ -74,7 +74,6 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' groupIds: [ 'vault' ] - requestMessage: '' } } ] diff --git a/avm/res/network/private-endpoint/tests/e2e/max/main.test.bicep b/avm/res/network/private-endpoint/tests/e2e/max/main.test.bicep index 65339afdbc..7b3e0e4fd8 100644 --- a/avm/res/network/private-endpoint/tests/e2e/max/main.test.bicep +++ b/avm/res/network/private-endpoint/tests/e2e/max/main.test.bicep @@ -117,7 +117,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' groupIds: [ 'vault' ] - requestMessage: '' + requestMessage: 'Hey there' } } ] diff --git a/avm/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep index b087066712..2c1fda4447 100644 --- a/avm/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep @@ -93,7 +93,6 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' groupIds: [ 'vault' ] - requestMessage: '' } } ] From 1436704cd5b9ccb06783833655daae16decf98ce Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Wed, 29 Nov 2023 18:03:35 +0100 Subject: [PATCH 14/22] fix: Diverse Bugfixes & improved `module.test.ps1` efficiency (#646) ## Description - Removed original caching solution and replaced it with a multi-threaded solution that compiles are required files once in the beginning - Removed redundant test file script (formerly required to support `parameter.json` files) - Fixed API tests - Fixed local test file paths > Runtime **before** change > 1. 14.4s > 2. 14.9s > 3. 15.9s > > Runtime **after** change > 1. 10.7s > 1. 7.3s > 1. 7.4s | Pipeline | | - | | [![avm.res.key-vault.vault](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2FtestSpeedUp-20231117&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) | --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> Co-authored-by: ChrisSidebotham-MSFT <48600046+ChrisSidebotham@users.noreply.github.com> --- .../avm-getModuleTestFiles/action.yml | 16 +- .../sharedScripts/Get-ModuleTestFileList.ps1 | 61 ------- .../sharedScripts/Set-ModuleReadMe.ps1 | 3 +- .../compliance/helper/helper.psm1 | 1 - .../compliance/module.tests.ps1 | 161 +++++------------- avm/utilities/tools/Test-ModuleLocally.ps1 | 4 +- 6 files changed, 50 insertions(+), 196 deletions(-) delete mode 100644 avm/utilities/pipelines/sharedScripts/Get-ModuleTestFileList.ps1 diff --git a/.github/actions/templates/avm-getModuleTestFiles/action.yml b/.github/actions/templates/avm-getModuleTestFiles/action.yml index bcfc36b307..2e0a37ebe2 100644 --- a/.github/actions/templates/avm-getModuleTestFiles/action.yml +++ b/.github/actions/templates/avm-getModuleTestFiles/action.yml @@ -21,17 +21,17 @@ runs: # Grouping task logs Write-Output '::group::Get parameter files' # Load used functions - . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'sharedScripts' 'Get-ModuleTestFileList.ps1') - $functionInput = @{ - ModulePath = Join-Path $env:GITHUB_WORKSPACE '${{ inputs.modulePath }}' - } + # Get the list of parameter file paths + $moduleFolderPath = Join-Path $env:GITHUB_WORKSPACE '${{ inputs.modulePath }}' + $testFilePaths = (Get-ChildItem -Path $moduleFolderPath -Recurse -Filter 'main.test.bicep').FullName | Sort-Object - Write-Verbose "Invoke task with" -Verbose - Write-Verbose ($functionInput | ConvertTo-Json | Out-String) -Verbose + $testFilePaths = $testFilePaths | ForEach-Object { + $_.Replace($moduleFolderPath, '').Trim('\').Trim('/') + } - # Get the list of parameter file paths - $testFilePaths = Get-ModuleTestFileList @functionInput -Verbose + Write-Verbose 'Found module test files' -Verbose + $testFilePaths | ForEach-Object { Write-Verbose "- [$_]" -Verbose } # Output values to be accessed by next jobs $compressedOutput = $testFilePaths | ConvertTo-Json -Compress diff --git a/avm/utilities/pipelines/sharedScripts/Get-ModuleTestFileList.ps1 b/avm/utilities/pipelines/sharedScripts/Get-ModuleTestFileList.ps1 deleted file mode 100644 index 252f90aafb..0000000000 --- a/avm/utilities/pipelines/sharedScripts/Get-ModuleTestFileList.ps1 +++ /dev/null @@ -1,61 +0,0 @@ -<# -.SYNOPSIS -Get the relative file paths of all test files in the given module. - -.DESCRIPTION -Get the relative file paths of all test files (*.json / main.test.bicep) in the given module. -The relative path is returned instead of the full one to make paths easier to read in the pipeline. - -.PARAMETER ModulePath -Mandatory. The module path to search in. - -.PARAMETER SearchFolder -Optional. The folder to search for files in - -.PARAMETER TestFilePattern -Optional. The pattern of test files to search for. For example '*.json' - -.EXAMPLE -Get-ModuleTestFileList -ModulePath 'C:\ResourceModules\modules\compute\virtual-machine' - -Returns the relative file paths of all test files of the virtual-machine module in the default test folder ('tests'). - -.EXAMPLE -Get-ModuleTestFileList -ModulePath 'C:\ResourceModules\modules\compute\virtual-machine' -SearchFolder 'parameters' - -Returns the relative file paths of all test files of the virtual-machine module in folder 'parameters'. -#> -function Get-ModuleTestFileList { - - [CmdletBinding()] - param ( - [Parameter(Mandatory)] - [string] $ModulePath, - - [Parameter(Mandatory = $false)] - [string] $SearchFolder = 'tests/e2e', - - [Parameter(Mandatory = $false)] - [string[]] $TestFilePattern = @('main.test.bicep') - ) - - $deploymentTests = @() - if (Test-Path (Join-Path $ModulePath $SearchFolder)) { - $deploymentTests += (Get-ChildItem -Path (Join-Path $ModulePath $SearchFolder) -Recurse -Include $TestFilePattern -File).FullName | Where-Object { - $_ -ne (Join-Path (Join-Path $ModulePath $SearchFolder) 'main.test.bicep') # Excluding PBR test file - } - } - - if (-not $deploymentTests) { - throw "No deployment test files found for module [$ModulePath]" - } - - $deploymentTests = $deploymentTests | ForEach-Object { - $_.Replace($ModulePath, '').Trim('\').Trim('/') - } - - Write-Verbose 'Found parameter files' - $deploymentTests | ForEach-Object { Write-Verbose "- $_" } - - return $deploymentTests -} diff --git a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 index d253e6f428..41566dae9a 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 @@ -1173,7 +1173,7 @@ function Set-UsageExamplesSection { $moduleNameCamelCase = $First.Tolower() + (Get-Culture).TextInfo.ToTitleCase($Rest) -Replace '-' } - $testFilePaths = Get-ModuleTestFileList -ModulePath $moduleRoot | ForEach-Object { Join-Path $moduleRoot $_ } + $testFilePaths = (Get-ChildItem -Path $ModuleRoot -Recurse -Filter 'main.test.bicep').FullName | Sort-Object $RequiredParametersList = $TemplateFileContent.parameters.Keys | Where-Object { Get-IsParameterRequired -TemplateFileContent $TemplateFileContent -Parameter $TemplateFileContent.parameters[$_] @@ -1627,7 +1627,6 @@ function Set-ModuleReadMe { # Load external functions . (Join-Path $PSScriptRoot 'Get-NestedResourceList.ps1') - . (Join-Path $PSScriptRoot 'Get-ModuleTestFileList.ps1') . (Join-Path $PSScriptRoot 'helper' 'Merge-FileWithNewContent.ps1') . (Join-Path $PSScriptRoot 'helper' 'Get-IsParameterRequired.ps1') . (Join-Path $PSScriptRoot 'helper' 'Get-SpecsAlignedResourceName.ps1') diff --git a/avm/utilities/pipelines/staticValidation/compliance/helper/helper.psm1 b/avm/utilities/pipelines/staticValidation/compliance/helper/helper.psm1 index b32a6a1e9d..305fb572de 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/helper/helper.psm1 +++ b/avm/utilities/pipelines/staticValidation/compliance/helper/helper.psm1 @@ -5,7 +5,6 @@ $repoRootPath = (Get-Item $PSScriptRoot).Parent.Parent.Parent.Parent.Parent.Pare . (Join-Path $repoRootPath 'avm' 'utilities' 'pipelines' 'sharedScripts' 'Get-NestedResourceList.ps1') . (Join-Path $repoRootPath 'avm' 'utilities' 'pipelines' 'sharedScripts' 'Get-ScopeOfTemplateFile.ps1') -. (Join-Path $repoRootPath 'avm' 'utilities' 'pipelines' 'sharedScripts' 'Get-ModuleTestFileList.ps1') . (Join-Path $repoRootPath 'avm' 'utilities' 'pipelines' 'sharedScripts' 'Get-PipelineFileName.ps1') . (Join-Path $repoRootPath 'avm' 'utilities' 'pipelines' 'sharedScripts' 'helper' 'Get-IsParameterRequired.ps1') . (Join-Path $repoRootPath 'avm' 'utilities' 'pipelines' 'sharedScripts' 'helper' 'ConvertTo-OrderedHashtable.ps1') diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index a7bb93b160..097acbce2a 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -20,12 +20,9 @@ $script:RgDeploymentSchema = 'https://schema.management.azure.com/schemas/2019-0 $script:SubscriptionDeploymentSchema = 'https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#' $script:MgDeploymentSchema = 'https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#' $script:TenantDeploymentSchema = 'https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#' -$script:moduleFolderPaths = $moduleFolderPaths $script:telemetryResCsvLink = 'https://aka.ms/avm/index/bicep/res/csv' $script:telemetryPtnCsvLink = 'https://aka.ms/avm/index/bicep/ptn/csv' - -# For runtime purposes, we cache the compiled template in a hashtable that uses a formatted relative module path as a key -$script:convertedTemplates = @{} +$script:moduleFolderPaths = $moduleFolderPaths # Shared exception messages $script:bicepTemplateCompilationFailedException = "Unable to compile the main.bicep template's content. This can happen if there is an error in the template. Please check if you can run the command ``bicep build {0} --stdout | ConvertFrom-Json -AsHashtable``." # -f $templateFilePath @@ -34,6 +31,24 @@ $script:templateNotFoundException = 'No template file found in folder [{0}]' # - # Import any helper function used in this test script Import-Module (Join-Path $PSScriptRoot 'helper' 'helper.psm1') -Force +# Building all required files for tests to optimize performance (using thread-safe multithreading) to consume later +# Collecting paths +$pathsToBuild = [System.Collections.ArrayList]@() +$pathsToBuild += $moduleFolderPaths | ForEach-Object { Join-Path $_ 'main.bicep' } +foreach ($moduleFolderPath in $moduleFolderPaths) { + if ($testFilePaths = ((Get-ChildItem -Path $moduleFolderPath -Recurse -Filter 'main.test.bicep').FullName | Sort-Object)) { + $pathsToBuild += $testFilePaths + } +} + +# building paths +$builtTestFileMap = [System.Collections.Concurrent.ConcurrentDictionary[string, object]]::new() +$pathsToBuild | ForEach-Object -Parallel { + $dict = $using:builtTestFileMap + $builtTemplate = bicep build $_ --stdout | ConvertFrom-Json -AsHashtable + $null = $dict.TryAdd($_, $builtTemplate) +} + Describe 'File/folder tests' -Tag 'Modules' { Context 'General module folder tests' { @@ -238,33 +253,12 @@ Describe 'Module tests' -Tag 'Module' { foreach ($moduleFolderPath in $moduleFolderPaths) { - # For runtime purposes, we cache the compiled template in a hashtable that uses a formatted relative module path as a key - $moduleFolderPathKey = $moduleFolderPath.Replace('\', '/').Split('/avm/')[1].Trim('/').Replace('/', '-') - if (-not ($convertedTemplates.Keys -contains $moduleFolderPathKey)) { - if (Test-Path (Join-Path $moduleFolderPath 'main.bicep')) { - $templateFilePath = Join-Path $moduleFolderPath 'main.bicep' - $templateContent = bicep build $templateFilePath --stdout | ConvertFrom-Json -AsHashtable - - if (-not $templateContent) { - throw ($bicepTemplateCompilationFailedException -f $templateFilePath) - } - } else { - throw ($templateNotFoundException -f $moduleFolderPath) - } - $convertedTemplates[$moduleFolderPathKey] = @{ - templateFilePath = $templateFilePath - templateContent = $templateContent - } - } else { - $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent - $templateFilePath = $convertedTemplates[$moduleFolderPathKey].templateFilePath - } - $resourceTypeIdentifier = ($moduleFolderPath -split '[\/|\\]{1}avm[\/|\\]{1}(res|ptn)[\/|\\]{1}')[2] -replace '\\', '/' # avm/res// + $templateFilePath = Join-Path $moduleFolderPath 'main.bicep' $readmeFileTestCases += @{ moduleFolderName = $resourceTypeIdentifier - templateContent = $templateContent + templateContent = $builtTestFileMap[$templateFilePath] templateFilePath = $templateFilePath readMeFilePath = Join-Path -Path $moduleFolderPath 'README.md' } @@ -367,27 +361,8 @@ Describe 'Module tests' -Tag 'Module' { $deploymentFolderTestCases = [System.Collections.ArrayList] @() foreach ($moduleFolderPath in $moduleFolderPaths) { - # For runtime purposes, we cache the compiled template in a hashtable that uses a formatted relative module path as a key - $moduleFolderPathKey = $moduleFolderPath.Replace('\', '/').Split('/avm/')[1].Trim('/').Replace('/', '-') - if (-not ($convertedTemplates.Keys -contains $moduleFolderPathKey)) { - if (Test-Path (Join-Path $moduleFolderPath 'main.bicep')) { - $templateFilePath = Join-Path $moduleFolderPath 'main.bicep' - $templateContent = bicep build $templateFilePath --stdout | ConvertFrom-Json -AsHashtable - - if (-not $templateContent) { - throw ($bicepTemplateCompilationFailedException -f $templateFilePath) - } - } else { - throw ($templateNotFoundException -f $moduleFolderPath) - } - $convertedTemplates[$moduleFolderPathKey] = @{ - templateFilePath = $templateFilePath - templateContent = $templateContent - } - } else { - $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent - $templateFilePath = $convertedTemplates[$moduleFolderPathKey].templateFilePath - } + $templateFilePath = Join-Path $moduleFolderPath 'main.bicep' + $templateContent = $builtTestFileMap[$templateFilePath] # Parameter file test cases $testFileTestCases = @() @@ -397,11 +372,11 @@ Describe 'Module tests' -Tag 'Module' { if (Test-Path (Join-Path $moduleFolderPath 'tests')) { - # Can be removed after full migration to bicep test files - $moduleTestFilePaths = Get-ModuleTestFileList -ModulePath $moduleFolderPath | ForEach-Object { Join-Path $moduleFolderPath $_ } + # TODO: Can be removed after full migration to bicep test files + $moduleTestFilePaths = (Get-ChildItem -Path $moduleFolderPath -Recurse -Filter 'main.test.bicep').FullName | Sort-Object foreach ($moduleTestFilePath in $moduleTestFilePaths) { - $deploymentFileContent = bicep build $moduleTestFilePath --stdout | ConvertFrom-Json -AsHashtable + $deploymentFileContent = $builtTestFileMap[$moduleTestFilePath] $deploymentTestFile_AllParameterNames = $deploymentFileContent.resources[-1].properties.parameters.Keys | Sort-Object # The last resource should be the test $testFileTestCases += @{ @@ -940,26 +915,8 @@ Describe 'Module tests' -Tag 'Module' { foreach ($moduleFolderPath in $moduleFolderPaths) { $resourceTypeIdentifier = ($moduleFolderPath -split '[\/|\\]{1}avm[\/|\\]{1}(res|ptn)[\/|\\]{1}')[2] -replace '\\', '/' # avm/res// - - # For runtime purposes, we cache the compiled template in a hashtable that uses a formatted relative module path as a key - $moduleFolderPathKey = $moduleFolderPath.Replace('\', '/').Split('/avm/')[1].Trim('/').Replace('/', '-') - if (-not ($convertedTemplates.Keys -contains $moduleFolderPathKey)) { - if (Test-Path (Join-Path $moduleFolderPath 'main.bicep')) { - $templateFilePath = Join-Path $moduleFolderPath 'main.bicep' - $templateContent = bicep build $templateFilePath --stdout | ConvertFrom-Json -AsHashtable - - if (-not $templateContent) { - throw ($bicepTemplateCompilationFailedException -f $templateFilePath) - } - } else { - throw ($templateNotFoundException -f $moduleFolderPath) - } - $convertedTemplates[$moduleFolderPathKey] = @{ - templateContent = $templateContent - } - } else { - $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent - } + $templateFilePath = Join-Path $moduleFolderPath 'main.bicep' + $templateContent = $builtTestFileMap[$templateFilePath] $metadataFileTestCases += @{ moduleFolderName = $resourceTypeIdentifier @@ -1008,28 +965,8 @@ Describe 'Module tests' -Tag 'Module' { foreach ($moduleFolderPath in $moduleFolderPaths) { $resourceTypeIdentifier = ($moduleFolderPath -split '[\/|\\]{1}avm[\/|\\]{1}(res|ptn)[\/|\\]{1}')[2] -replace '\\', '/' # avm/res// - - # For runtime purposes, we cache the compiled template in a hashtable that uses a formatted relative module path as a key - $moduleFolderPathKey = $moduleFolderPath.Replace('\', '/').Split('/avm/')[1].Trim('/').Replace('/', '-') - if (-not ($convertedTemplates.Keys -contains $moduleFolderPathKey)) { - if (Test-Path (Join-Path $moduleFolderPath 'main.bicep')) { - $templateFilePath = Join-Path $moduleFolderPath 'main.bicep' - $templateContent = bicep build $templateFilePath --stdout | ConvertFrom-Json -AsHashtable - - if (-not $templateContent) { - throw ($bicepTemplateCompilationFailedException -f $templateFilePath) - } - } else { - throw ($templateNotFoundException -f $moduleFolderPath) - } - $convertedTemplates[$moduleFolderPathKey] = @{ - templateContent = $templateContent - templateFilePath = $templateFilePath - } - } else { - $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent - $templateFilePath = $convertedTemplates[$moduleFolderPathKey].templateFilePath - } + $templateFilePath = Join-Path $moduleFolderPath 'main.bicep' + $templateContent = $builtTestFileMap[$templateFilePath] $udtSpecificTestCases += @{ moduleFolderName = $resourceTypeIdentifier @@ -1198,7 +1135,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { foreach ($moduleFolderPath in $moduleFolderPaths) { if (Test-Path (Join-Path $moduleFolderPath 'tests')) { - $testFilePaths = Get-ModuleTestFileList -ModulePath $moduleFolderPath | ForEach-Object { Join-Path $moduleFolderPath $_ } + $testFilePaths = (Get-ChildItem -Path $moduleFolderPath -Recurse -Filter 'main.test.bicep').FullName | Sort-Object foreach ($testFilePath in $testFilePaths) { $testFileContent = Get-Content $testFilePath $resourceTypeIdentifier = ($moduleFolderPath -split '[\/|\\]{1}avm[\/|\\]{1}(res|ptn)[\/|\\]{1}')[2] -replace '\\', '/' # avm/res// @@ -1337,28 +1274,8 @@ Describe 'API version tests' -Tag 'ApiCheck' { foreach ($moduleFolderPath in $moduleFolderPaths) { $moduleFolderName = $moduleFolderPath.Replace('\', '/').Split('/avm/')[1] - - # For runtime purposes, we cache the compiled template in a hashtable that uses a formatted relative module path as a key - $moduleFolderPathKey = $moduleFolderPath.Replace('\', '/').Split('/avm/')[1].Trim('/').Replace('/', '-') - if (-not ($convertedTemplates.Keys -contains $moduleFolderPathKey)) { - if (Test-Path (Join-Path $moduleFolderPath 'main.bicep')) { - $templateFilePath = Join-Path $moduleFolderPath 'main.bicep' - $templateContent = bicep build $templateFilePath --stdout | ConvertFrom-Json -AsHashtable - - if (-not $templateContent) { - throw ($bicepTemplateCompilationFailedException -f $templateFilePath) - } - } else { - throw ($templateNotFoundException -f $moduleFolderPath) - } - $convertedTemplates[$moduleFolderPathKey] = @{ - templateFilePath = $templateFilePath - templateContent = $templateContent - } - } else { - $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent - $templateFilePath = $convertedTemplates[$moduleFolderPathKey].templateFilePath - } + $templateFilePath = Join-Path $moduleFolderPath 'main.bicep' + $templateContent = $builtTestFileMap[$templateFilePath] $nestedResources = Get-NestedResourceList -TemplateFileContent $templateContent | Where-Object { $_.type -notin @('Microsoft.Resources/deployments') -and $_ @@ -1370,7 +1287,7 @@ Describe 'API version tests' -Tag 'ApiCheck' { { $PSItem -like '*diagnosticsettings*' } { $testCases += @{ moduleName = $moduleFolderName - resourceType = 'diagnosticsettings' + resourceType = 'diagnosticSettings' ProviderNamespace = 'Microsoft.Insights' TargetApi = $resource.ApiVersion AvailableApiVersions = $ApiVersions @@ -1392,7 +1309,7 @@ Describe 'API version tests' -Tag 'ApiCheck' { { $PSItem -like '*roleAssignments' } { $testCases += @{ moduleName = $moduleFolderName - resourceType = 'roleassignments' + resourceType = 'roleAssignments' ProviderNamespace = 'Microsoft.Authorization' TargetApi = $resource.ApiVersion AvailableApiVersions = $ApiVersions @@ -1434,16 +1351,16 @@ Describe 'API version tests' -Tag 'ApiCheck' { [string] $ResourceType, [string] $TargetApi, [string] $ProviderNamespace, - [PSCustomObject] $AvailableApiVersions, + [hashtable] $AvailableApiVersions, [bool] $AllowPreviewVersionsInAPITests ) - if (-not (($AvailableApiVersions | Get-Member -Type NoteProperty).Name -contains $ProviderNamespace)) { + if ($AvailableApiVersions.Keys -notcontains $ProviderNamespace) { Write-Warning "[API Test] The Provider Namespace [$ProviderNamespace] is missing in your Azure API versions file. Please consider updating it and if it is still missing to open an issue in the 'AzureAPICrawler' PowerShell module's GitHub repository." Set-ItResult -Skipped -Because "The Azure API version file is missing the Provider Namespace [$ProviderNamespace]." return } - if (-not (($AvailableApiVersions.$ProviderNamespace | Get-Member -Type NoteProperty).Name -contains $ResourceType)) { + if ($AvailableApiVersions.$ProviderNamespace.Keys -notcontains $ResourceType) { Write-Warning "[API Test] The Provider Namespace [$ProviderNamespace] is missing the Resource Type [$ResourceType] in your API versions file. Please consider updating it and if it is still missing to open an issue in the 'AzureAPICrawler' PowerShell module's GitHub repository." Set-ItResult -Skipped -Because "The Azure API version file is missing the Resource Type [$ResourceType] for Provider Namespace [$ProviderNamespace]." return @@ -1468,7 +1385,7 @@ Describe 'API version tests' -Tag 'ApiCheck' { $approvedApiVersions = $approvedApiVersions | Sort-Object -Unique -Descending - if ( $approvedApiVersions -notcontains $TargetApi) { + if ($approvedApiVersions -notcontains $TargetApi) { # Using a warning now instead of an error, as we don't want to block PRs for this. Write-Warning ("The used API version [$TargetApi] is not one of the most recent 5 versions. Please consider upgrading to one of the following: {0}" -f $approvedApiVersions -join ', ') diff --git a/avm/utilities/tools/Test-ModuleLocally.ps1 b/avm/utilities/tools/Test-ModuleLocally.ps1 index 7d23be4b67..d2a5f612f9 100644 --- a/avm/utilities/tools/Test-ModuleLocally.ps1 +++ b/avm/utilities/tools/Test-ModuleLocally.ps1 @@ -151,7 +151,7 @@ function Test-ModuleLocally { [string] $ModuleTestFilePath = (Join-Path (Split-Path $TemplateFilePath -Parent) '.test'), [Parameter(Mandatory = $false)] - [string] $PesterTestFilePath = 'utilities/pipelines/staticValidation/module.tests.ps1', + [string] $PesterTestFilePath = 'avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1', [Parameter(Mandatory = $false)] [Psobject] $ValidateOrDeployParameters = @{}, @@ -173,7 +173,7 @@ function Test-ModuleLocally { ) begin { - $repoRootPath = (Get-Item $PSScriptRoot).Parent.Parent + $repoRootPath = (Get-Item $PSScriptRoot).Parent.Parent.Parent.FullName $ModuleName = Split-Path (Split-Path $TemplateFilePath -Parent) -Leaf $utilitiesFolderPath = Split-Path $PSScriptRoot -Parent Write-Verbose "Running local tests for [$ModuleName]" From 1180d89abb307b01a8996e5c211abaefd0c2f257 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Thu, 30 Nov 2023 07:34:41 +0100 Subject: [PATCH 15/22] feat: Moved `Get-BRMRepositoryName` to `SharedScripts` (#682) ## Description - Moved `Get-BRMRepositoryName` to `SharedScripts` - Tested all 5 invocations to ensure the new paths are resolved correctly --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 | 2 +- avm/utilities/pipelines/publish/Publish-ModuleFromTagToPBR.ps1 | 2 +- .../{publish/helper => sharedScripts}/Get-BRMRepositoryName.ps1 | 0 avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 | 2 +- .../pipelines/staticValidation/compliance/helper/helper.psm1 | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename avm/utilities/pipelines/{publish/helper => sharedScripts}/Get-BRMRepositoryName.ps1 (100%) diff --git a/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 b/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 index 1f5fc4a5c0..84d0029db6 100644 --- a/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 +++ b/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 @@ -33,7 +33,7 @@ function Publish-ModuleFromPathToPBR { # Load used functions . (Join-Path $PSScriptRoot 'helper' 'Get-ModulesToPublish.ps1') . (Join-Path $PSScriptRoot 'helper' 'Get-ModuleTargetVersion.ps1') - . (Join-Path $PSScriptRoot 'helper' 'Get-BRMRepositoryName.ps1') + . (Join-Path (Split-Path $PSScriptRoot) 'sharedScripts' 'Get-BRMRepositoryName.ps1') . (Join-Path $PSScriptRoot 'helper' 'New-ModuleReleaseTag.ps1') . (Join-Path $PSScriptRoot 'helper' 'Get-ModuleReadmeLink.ps1') . (Join-Path (Split-Path $PSScriptRoot -Parent) 'sharedScripts' 'tokenReplacement' 'Convert-TokensInFileList.ps1') diff --git a/avm/utilities/pipelines/publish/Publish-ModuleFromTagToPBR.ps1 b/avm/utilities/pipelines/publish/Publish-ModuleFromTagToPBR.ps1 index 7af3b98b51..3c692f07c3 100644 --- a/avm/utilities/pipelines/publish/Publish-ModuleFromTagToPBR.ps1 +++ b/avm/utilities/pipelines/publish/Publish-ModuleFromTagToPBR.ps1 @@ -10,7 +10,7 @@ function Publish-ModuleFromTagToPBR { ) # Load used functions - . (Join-Path $PSScriptRoot 'helper' 'Get-BRMRepositoryName.ps1') + . (Join-Path (Split-Path $PSScriptRoot) 'sharedScripts' 'Get-BRMRepositoryName.ps1') . (Join-Path $PSScriptRoot 'helper' 'Get-ModuleReadmeLink.ps1') . (Join-Path (Split-Path $PSScriptRoot -Parent) 'sharedScripts' 'tokenReplacement' 'Convert-TokensInFileList.ps1') diff --git a/avm/utilities/pipelines/publish/helper/Get-BRMRepositoryName.ps1 b/avm/utilities/pipelines/sharedScripts/Get-BRMRepositoryName.ps1 similarity index 100% rename from avm/utilities/pipelines/publish/helper/Get-BRMRepositoryName.ps1 rename to avm/utilities/pipelines/sharedScripts/Get-BRMRepositoryName.ps1 diff --git a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 index 41566dae9a..2afb123a5d 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 @@ -1631,7 +1631,7 @@ function Set-ModuleReadMe { . (Join-Path $PSScriptRoot 'helper' 'Get-IsParameterRequired.ps1') . (Join-Path $PSScriptRoot 'helper' 'Get-SpecsAlignedResourceName.ps1') . (Join-Path $PSScriptRoot 'helper' 'ConvertTo-OrderedHashtable.ps1') - . (Join-Path (Split-Path $PSScriptRoot -Parent) 'publish' 'helper' 'Get-BRMRepositoryName.ps1') + . (Join-Path $PSScriptRoot 'Get-BRMRepositoryName.ps1') # Check template & make full path $TemplateFilePath = Resolve-Path -Path $TemplateFilePath -ErrorAction Stop diff --git a/avm/utilities/pipelines/staticValidation/compliance/helper/helper.psm1 b/avm/utilities/pipelines/staticValidation/compliance/helper/helper.psm1 index 305fb572de..f176c4a707 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/helper/helper.psm1 +++ b/avm/utilities/pipelines/staticValidation/compliance/helper/helper.psm1 @@ -9,7 +9,7 @@ $repoRootPath = (Get-Item $PSScriptRoot).Parent.Parent.Parent.Parent.Parent.Pare . (Join-Path $repoRootPath 'avm' 'utilities' 'pipelines' 'sharedScripts' 'helper' 'Get-IsParameterRequired.ps1') . (Join-Path $repoRootPath 'avm' 'utilities' 'pipelines' 'sharedScripts' 'helper' 'ConvertTo-OrderedHashtable.ps1') . (Join-Path $repoRootPath 'avm' 'utilities' 'pipelines' 'sharedScripts' 'helper' 'Get-CrossReferencedModuleList.ps1') -. (Join-Path $repoRootPath 'avm' 'utilities' 'pipelines' 'publish' 'helper' 'Get-BRMRepositoryName.ps1') +. (Join-Path $repoRootPath 'avm' 'utilities' 'pipelines' 'sharedScripts' 'Get-BRMRepositoryName.ps1') #################################### # Load test-specific functions # From 4aff3901fcc11f71837f4ff62517e3841b9a968a Mon Sep 17 00:00:00 2001 From: Seif Bassem <38246040+sebassem@users.noreply.github.com> Date: Thu, 30 Nov 2023 12:01:50 +0200 Subject: [PATCH 16/22] feat: New Module avm-res-resources-deployment-script (#604) ## Description New Module migrated from CARML [![avm.res.resources.deployment-script](https://github.com/sebassem/bicep-registry-modules/actions/workflows/avm.res.resources.deployment-script.yml/badge.svg?branch=avm-deployment-scripts)](https://github.com/sebassem/bicep-registry-modules/actions/workflows/avm.res.resources.deployment-script.yml) --------- Co-authored-by: Alexander Sehr Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> Co-authored-by: ChrisSidebotham-MSFT <48600046+ChrisSidebotham@users.noreply.github.com> --- .github/CODEOWNERS | 2 +- .../avm.res.resources.deployment-script.yml | 81 ++ avm/res/resources/deployment-script/README.md | 1007 +++++++++++++++++ .../resources/deployment-script/main.bicep | 266 +++++ avm/res/resources/deployment-script/main.json | 450 ++++++++ .../tests/e2e/cli/dependencies.bicep | 31 + .../tests/e2e/cli/main.test.bicep | 73 ++ .../tests/e2e/defaults/dependencies.bicep | 31 + .../tests/e2e/defaults/main.test.bicep | 68 ++ .../tests/e2e/max/dependencies.bicep | 33 + .../tests/e2e/max/main.test.bicep | 107 ++ .../e2e/private-network/dependencies.bicep | 102 ++ .../tests/e2e/private-network/main.test.bicep | 72 ++ .../tests/e2e/ps/dependencies.bicep | 31 + .../tests/e2e/ps/main.test.bicep | 66 ++ .../tests/e2e/waf-aligned/dependencies.bicep | 38 + .../tests/e2e/waf-aligned/main.test.bicep | 80 ++ .../resources/deployment-script/version.json | 7 + 18 files changed, 2544 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/avm.res.resources.deployment-script.yml create mode 100644 avm/res/resources/deployment-script/README.md create mode 100644 avm/res/resources/deployment-script/main.bicep create mode 100644 avm/res/resources/deployment-script/main.json create mode 100644 avm/res/resources/deployment-script/tests/e2e/cli/dependencies.bicep create mode 100644 avm/res/resources/deployment-script/tests/e2e/cli/main.test.bicep create mode 100644 avm/res/resources/deployment-script/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/res/resources/deployment-script/tests/e2e/defaults/main.test.bicep create mode 100644 avm/res/resources/deployment-script/tests/e2e/max/dependencies.bicep create mode 100644 avm/res/resources/deployment-script/tests/e2e/max/main.test.bicep create mode 100644 avm/res/resources/deployment-script/tests/e2e/private-network/dependencies.bicep create mode 100644 avm/res/resources/deployment-script/tests/e2e/private-network/main.test.bicep create mode 100644 avm/res/resources/deployment-script/tests/e2e/ps/dependencies.bicep create mode 100644 avm/res/resources/deployment-script/tests/e2e/ps/main.test.bicep create mode 100644 avm/res/resources/deployment-script/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/res/resources/deployment-script/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/res/resources/deployment-script/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 726c670aff..cb0cf8e4cd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -120,7 +120,7 @@ #/avm/res/recovery-services/vault/ @Azure/avm-res-recoveryservices-vault-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/relay/namespace/ @Azure/avm-res-relay-namespace-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/resource-graph/query/ @Azure/avm-res-resourcegraph-query-module-owners-bicep @Azure/avm-core-team-technical-bicep -#/avm/res/resources/deployment-script/ @Azure/avm-res-resources-deploymentscript-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/res/resources/deployment-script/ @Azure/avm-res-resources-deploymentscript-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/resources/resource-group/ @Azure/avm-res-resources-resourcegroup-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/resources/tags/ @Azure/avm-res-resources-tags-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/search/search-service/ @Azure/avm-res-search-searchservice-module-owners-bicep @Azure/avm-core-team-technical-bicep diff --git a/.github/workflows/avm.res.resources.deployment-script.yml b/.github/workflows/avm.res.resources.deployment-script.yml new file mode 100644 index 0000000000..8a696d2ab0 --- /dev/null +++ b/.github/workflows/avm.res.resources.deployment-script.yml @@ -0,0 +1,81 @@ +name: "avm.res.resources.deployment-script" + +on: + schedule: + - cron: "0 12 1/15 * *" # Bi-Weekly Test (on 1st & 15th of month) + 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 + + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.resources.deployment-script" + - "avm/res/resources/deployment-script/**" + - "avm/utilities/pipelines/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/resources/deployment-script" + workflowPath: ".github/workflows/avm.res.resources.deployment-script" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-20.04 + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get parameter file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Module" + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/res/resources/deployment-script/README.md b/avm/res/resources/deployment-script/README.md new file mode 100644 index 0000000000..57e1557f0e --- /dev/null +++ b/avm/res/resources/deployment-script/README.md @@ -0,0 +1,1007 @@ +# Deployment Scripts `[Microsoft.Resources/deploymentScripts]` + +This module deploys Deployment Scripts. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| 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/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Resources/deploymentScripts` | [2023-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Resources/deploymentScripts) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/resources/deployment-script:`. + +- [Using Azure CLI](#example-1-using-azure-cli) +- [Using only defaults](#example-2-using-only-defaults) +- [Using large parameter set](#example-3-using-large-parameter-set) +- [Using Private Networking](#example-4-using-private-networking) +- [Using Azure PowerShell](#example-5-using-azure-powershell) +- [WAF-aligned](#example-6-waf-aligned) + +### Example 1: _Using Azure CLI_ + +This instance deploys the module with an Azure CLI script. + + +

+ +via Bicep module + +```bicep +module deploymentScript 'br/public:avm/res/resources/deployment-script:' = { + name: '${uniqueString(deployment().name, location)}-test-rdscli' + params: { + // Required parameters + kind: 'AzureCLI' + name: 'rdscli001' + // Non-required parameters + azCliVersion: '2.9.1' + environmentVariables: { + secureList: [ + { + name: 'var1' + value: 'AVM Deployment Script test!' + } + ] + } + location: '' + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } + retentionInterval: 'P1D' + scriptContent: 'echo \'Enviornment variable value is: \' $var1' + storageAccountResourceId: '' + } +} +``` + +
+

+ +

+ +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 + "kind": { + "value": "AzureCLI" + }, + "name": { + "value": "rdscli001" + }, + // Non-required parameters + "azCliVersion": { + "value": "2.9.1" + }, + "environmentVariables": { + "value": { + "secureList": [ + { + "name": "var1", + "value": "AVM Deployment Script test!" + } + ] + } + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, + "retentionInterval": { + "value": "P1D" + }, + "scriptContent": { + "value": "echo \"Enviornment variable value is: \" $var1" + }, + "storageAccountResourceId": { + "value": "" + } + } +} +``` + +
+

+ +### Example 2: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. +> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. + + + +

+ +via Bicep module + +```bicep +module deploymentScript 'br/public:avm/res/resources/deployment-script:' = { + name: '${uniqueString(deployment().name, location)}-test-rdsmin' + params: { + // Required parameters + kind: 'AzurePowerShell' + name: 'rdsmin001' + // Non-required parameters + azPowerShellVersion: '9.7' + location: '' + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } + retentionInterval: 'P1D' + scriptContent: 'Write-Host \'AVM Deployment Script test!\'' + storageAccountResourceId: '' + } +} +``` + +
+

+ +

+ +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 + "kind": { + "value": "AzurePowerShell" + }, + "name": { + "value": "rdsmin001" + }, + // Non-required parameters + "azPowerShellVersion": { + "value": "9.7" + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, + "retentionInterval": { + "value": "P1D" + }, + "scriptContent": { + "value": "Write-Host \"AVM Deployment Script test!\"" + }, + "storageAccountResourceId": { + "value": "" + } + } +} +``` + +
+

+ +### Example 3: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module deploymentScript 'br/public:avm/res/resources/deployment-script:' = { + name: '${uniqueString(deployment().name, location)}-test-rdsmax' + params: { + // Required parameters + kind: 'AzureCLI' + name: 'rdsmax001' + // Non-required parameters + arguments: '-argument1 \\\'test\\\'' + azCliVersion: '2.9.1' + cleanupPreference: 'Always' + containerGroupName: 'dep-cg-rdsmax' + environmentVariables: { + secureList: [ + { + name: 'var1' + value: 'test' + } + { + name: 'var2' + secureValue: '' + } + ] + } + location: '' + lock: { + kind: 'None' + } + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } + retentionInterval: 'P1D' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + runOnce: true + scriptContent: 'echo \'AVM Deployment Script test!\'' + storageAccountResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + timeout: 'PT1H' + } +} +``` + +
+

+ +

+ +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 + "kind": { + "value": "AzureCLI" + }, + "name": { + "value": "rdsmax001" + }, + // Non-required parameters + "arguments": { + "value": "-argument1 \\\"test\\\"" + }, + "azCliVersion": { + "value": "2.9.1" + }, + "cleanupPreference": { + "value": "Always" + }, + "containerGroupName": { + "value": "dep-cg-rdsmax" + }, + "environmentVariables": { + "value": { + "secureList": [ + { + "name": "var1", + "value": "test" + }, + { + "name": "var2", + "secureValue": "" + } + ] + } + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "None" + } + }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, + "retentionInterval": { + "value": "P1D" + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "runOnce": { + "value": true + }, + "scriptContent": { + "value": "echo \"AVM Deployment Script test!\"" + }, + "storageAccountResourceId": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "timeout": { + "value": "PT1H" + } + } +} +``` + +
+

+ +### Example 4: _Using Private Networking_ + +This instance deploys the module with access to a private network. + + +

+ +via Bicep module + +```bicep +module deploymentScript 'br/public:avm/res/resources/deployment-script:' = { + name: '${uniqueString(deployment().name, location)}-test-rdsnet' + params: { + // Required parameters + kind: 'AzureCLI' + name: 'rdsnet001' + // Non-required parameters + azCliVersion: '2.9.1' + cleanupPreference: 'Always' + location: '' + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } + retentionInterval: 'P1D' + runOnce: true + scriptContent: 'echo \'AVM Deployment Script test!\'' + storageAccountResourceId: '' + subnetResourceIds: [ + '' + ] + timeout: 'PT1H' + } +} +``` + +
+

+ +

+ +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 + "kind": { + "value": "AzureCLI" + }, + "name": { + "value": "rdsnet001" + }, + // Non-required parameters + "azCliVersion": { + "value": "2.9.1" + }, + "cleanupPreference": { + "value": "Always" + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, + "retentionInterval": { + "value": "P1D" + }, + "runOnce": { + "value": true + }, + "scriptContent": { + "value": "echo \"AVM Deployment Script test!\"" + }, + "storageAccountResourceId": { + "value": "" + }, + "subnetResourceIds": { + "value": [ + "" + ] + }, + "timeout": { + "value": "PT1H" + } + } +} +``` + +
+

+ +### Example 5: _Using Azure PowerShell_ + +This instance deploys the module with an Azure PowerShell script. + + +

+ +via Bicep module + +```bicep +module deploymentScript 'br/public:avm/res/resources/deployment-script:' = { + name: '${uniqueString(deployment().name, location)}-test-rdsps' + params: { + // Required parameters + kind: 'AzurePowerShell' + name: 'rdsps001' + // Non-required parameters + arguments: '-var1 \\\'AVM Deployment Script test!\\\'' + azPowerShellVersion: '9.7' + location: '' + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } + retentionInterval: 'P1D' + scriptContent: 'param([string] $var1);Write-Host \'Argument var1 value is:\' $var1' + storageAccountResourceId: '' + } +} +``` + +
+

+ +

+ +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 + "kind": { + "value": "AzurePowerShell" + }, + "name": { + "value": "rdsps001" + }, + // Non-required parameters + "arguments": { + "value": "-var1 \\\"AVM Deployment Script test!\\\"" + }, + "azPowerShellVersion": { + "value": "9.7" + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, + "retentionInterval": { + "value": "P1D" + }, + "scriptContent": { + "value": "param([string] $var1);Write-Host \"Argument var1 value is:\" $var1" + }, + "storageAccountResourceId": { + "value": "" + } + } +} +``` + +
+

+ +### Example 6: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module deploymentScript 'br/public:avm/res/resources/deployment-script:' = { + name: '${uniqueString(deployment().name, location)}-test-rdswaf' + params: { + // Required parameters + kind: 'AzureCLI' + name: 'rdswaf001' + // Non-required parameters + azCliVersion: '2.9.1' + cleanupPreference: 'Always' + enableTelemetry: '' + location: '' + lock: { + kind: 'None' + } + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } + retentionInterval: 'P1D' + runOnce: true + scriptContent: 'echo \'AVM Deployment Script test!\'' + storageAccountResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + timeout: 'PT1H' + } +} +``` + +
+

+ +

+ +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 + "kind": { + "value": "AzureCLI" + }, + "name": { + "value": "rdswaf001" + }, + // Non-required parameters + "azCliVersion": { + "value": "2.9.1" + }, + "cleanupPreference": { + "value": "Always" + }, + "enableTelemetry": { + "value": "" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "None" + } + }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, + "retentionInterval": { + "value": "P1D" + }, + "runOnce": { + "value": true + }, + "scriptContent": { + "value": "echo \"AVM Deployment Script test!\"" + }, + "storageAccountResourceId": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "timeout": { + "value": "PT1H" + } + } +} +``` + +
+

+ + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-kind) | string | Specifies the Kind of the Deployment Script. | +| [`name`](#parameter-name) | string | Name of the Deployment Script. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`arguments`](#parameter-arguments) | string | Command-line arguments to pass to the script. Arguments are separated by spaces. | +| [`azCliVersion`](#parameter-azcliversion) | string | Azure CLI module version to be used. See a list of supported Azure CLI versions: https://mcr.microsoft.com/v2/azure-cli/tags/list. | +| [`azPowerShellVersion`](#parameter-azpowershellversion) | string | Azure PowerShell module version to be used. See a list of supported Azure PowerShell versions: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list. | +| [`cleanupPreference`](#parameter-cleanuppreference) | string | The clean up preference when the script execution gets in a terminal state. Specify the preference on when to delete the deployment script resources. The default value is Always, which means the deployment script resources are deleted despite the terminal state (Succeeded, Failed, canceled). | +| [`containerGroupName`](#parameter-containergroupname) | string | Container group name, if not specified then the name will get auto-generated. Not specifying a 'containerGroupName' indicates the system to generate a unique name which might end up flagging an Azure Policy as non-compliant. Use 'containerGroupName' when you have an Azure Policy that expects a specific naming convention or when you want to fully control the name. 'containerGroupName' property must be between 1 and 63 characters long, must contain only lowercase letters, numbers, and dashes and it cannot start or end with a dash and consecutive dashes are not allowed. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`environmentVariables`](#parameter-environmentvariables) | secureObject | The environment variables to pass over to the script. The list is passed as an object with a key name "secureList" and the value is the list of environment variables (array). The list must have a 'name' and a 'value' or a 'secretValue' property for each object. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | +| [`primaryScriptUri`](#parameter-primaryscripturi) | string | Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent instead. | +| [`retentionInterval`](#parameter-retentioninterval) | string | Interval for which the service retains the script resource after it reaches a terminal state. Resource will be deleted when this duration expires. Duration is based on ISO 8601 pattern (for example P7D means one week). | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`runOnce`](#parameter-runonce) | bool | When set to false, script will run every time the template is deployed. When set to true, the script will only run once. | +| [`scriptContent`](#parameter-scriptcontent) | string | Script body. Max length: 32000 characters. To run an external script, use primaryScriptURI instead. | +| [`storageAccountResourceId`](#parameter-storageaccountresourceid) | string | The resource ID of the storage account to use for this deployment script. If none is provided, the deployment script uses a temporary, managed storage account. | +| [`subnetResourceIds`](#parameter-subnetresourceids) | array | List of subnet IDs to use for the container group. This is required if you want to run the deployment script in a private network. | +| [`supportingScriptUris`](#parameter-supportingscripturis) | array | List of supporting files for the external script (defined in primaryScriptUri). Does not work with internal scripts (code defined in scriptContent). | +| [`tags`](#parameter-tags) | object | Resource tags. | +| [`timeout`](#parameter-timeout) | string | Maximum allowed script execution time specified in ISO 8601 format. Default value is PT1H - 1 hour; 'PT30M' - 30 minutes; 'P5D' - 5 days; 'P1Y' 1 year. | + +**Generated parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`baseTime`](#parameter-basetime) | string | Do not provide a value! This date value is used to make sure the script run every time the template is deployed. | + +### Parameter: `arguments` + +Command-line arguments to pass to the script. Arguments are separated by spaces. +- Required: No +- Type: string + +### Parameter: `azCliVersion` + +Azure CLI module version to be used. See a list of supported Azure CLI versions: https://mcr.microsoft.com/v2/azure-cli/tags/list. +- Required: No +- Type: string + +### Parameter: `azPowerShellVersion` + +Azure PowerShell module version to be used. See a list of supported Azure PowerShell versions: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list. +- Required: No +- Type: string + +### Parameter: `baseTime` + +Do not provide a value! This date value is used to make sure the script run every time the template is deployed. +- Required: No +- Type: string +- Default: `[utcNow('yyyy-MM-dd-HH-mm-ss')]` + +### Parameter: `cleanupPreference` + +The clean up preference when the script execution gets in a terminal state. Specify the preference on when to delete the deployment script resources. The default value is Always, which means the deployment script resources are deleted despite the terminal state (Succeeded, Failed, canceled). +- Required: No +- Type: string +- Default: `'Always'` +- Allowed: + ```Bicep + [ + 'Always' + 'OnExpiration' + 'OnSuccess' + ] + ``` + +### Parameter: `containerGroupName` + +Container group name, if not specified then the name will get auto-generated. Not specifying a 'containerGroupName' indicates the system to generate a unique name which might end up flagging an Azure Policy as non-compliant. Use 'containerGroupName' when you have an Azure Policy that expects a specific naming convention or when you want to fully control the name. 'containerGroupName' property must be between 1 and 63 characters long, must contain only lowercase letters, numbers, and dashes and it cannot start or end with a dash and consecutive dashes are not allowed. +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `environmentVariables` + +The environment variables to pass over to the script. The list is passed as an object with a key name "secureList" and the value is the list of environment variables (array). The list must have a 'name' and a 'value' or a 'secretValue' property for each object. +- Required: No +- Type: secureObject +- Default: `{}` + +### Parameter: `kind` + +Specifies the Kind of the Deployment Script. +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'AzureCLI' + 'AzurePowerShell' + ] + ``` + +### Parameter: `location` + +Location for all resources. +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. +- Required: No +- Type: object + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`kind`](#parameter-lockkind) | No | string | Optional. Specify the type of lock. | +| [`name`](#parameter-lockname) | No | string | Optional. Specify the name of lock. | + +### Parameter: `lock.kind` + +Optional. Specify the type of lock. + +- Required: No +- Type: string +- Allowed: `[CanNotDelete, None, ReadOnly]` + +### Parameter: `lock.name` + +Optional. Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. +- Required: No +- Type: object + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`userAssignedResourcesIds`](#parameter-managedidentitiesuserassignedresourcesids) | Yes | array | Optional. The resource ID(s) to assign to the resource. | + +### Parameter: `managedIdentities.userAssignedResourcesIds` + +Optional. The resource ID(s) to assign to the resource. + +- Required: Yes +- Type: array + +### Parameter: `name` + +Name of the Deployment Script. +- Required: Yes +- Type: string + +### Parameter: `primaryScriptUri` + +Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent instead. +- Required: No +- Type: string + +### Parameter: `retentionInterval` + +Interval for which the service retains the script resource after it reaches a terminal state. Resource will be deleted when this duration expires. Duration is based on ISO 8601 pattern (for example P7D means one week). +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. +- Required: No +- Type: array + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`condition`](#parameter-roleassignmentscondition) | No | string | 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" | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | No | string | Optional. Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | No | string | Optional. The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | No | string | Optional. The description of the role assignment. | +| [`principalId`](#parameter-roleassignmentsprincipalid) | Yes | string | Required. The principal ID of the principal (user/group/identity) to assign the role to. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | No | string | Optional. The principal type of the assigned principal ID. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | Yes | string | Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +### Parameter: `roleAssignments.condition` + +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" + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Optional. Version of the condition. + +- Required: No +- Type: string +- Allowed: `[2.0]` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +Optional. The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +Optional. The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalId` + +Required. The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.principalType` + +Optional. The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: `[Device, ForeignGroup, Group, ServicePrincipal, User]` + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `runOnce` + +When set to false, script will run every time the template is deployed. When set to true, the script will only run once. +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `scriptContent` + +Script body. Max length: 32000 characters. To run an external script, use primaryScriptURI instead. +- Required: No +- Type: string + +### Parameter: `storageAccountResourceId` + +The resource ID of the storage account to use for this deployment script. If none is provided, the deployment script uses a temporary, managed storage account. +- Required: No +- Type: string +- Default: `''` + +### Parameter: `subnetResourceIds` + +List of subnet IDs to use for the container group. This is required if you want to run the deployment script in a private network. +- Required: No +- Type: array + +### Parameter: `supportingScriptUris` + +List of supporting files for the external script (defined in primaryScriptUri). Does not work with internal scripts (code defined in scriptContent). +- Required: No +- Type: array + +### Parameter: `tags` + +Resource tags. +- Required: No +- Type: object + +### Parameter: `timeout` + +Maximum allowed script execution time specified in ISO 8601 format. Default value is PT1H - 1 hour; 'PT30M' - 30 minutes; 'P5D' - 5 days; 'P1Y' 1 year. +- Required: No +- Type: string + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployment script. | +| `outputs` | object | The output of the deployment script. | +| `resourceGroupName` | string | The resource group the deployment script was deployed into. | +| `resourceId` | string | The resource ID of the deployment script. | + +## Cross-referenced modules + +_None_ diff --git a/avm/res/resources/deployment-script/main.bicep b/avm/res/resources/deployment-script/main.bicep new file mode 100644 index 0000000000..001a97cc94 --- /dev/null +++ b/avm/res/resources/deployment-script/main.bicep @@ -0,0 +1,266 @@ +metadata name = 'Deployment Scripts' +metadata description = 'This module deploys Deployment Scripts.' +metadata owner = 'Azure/module-maintainers' + +// ================ // +// Parameters // +// ================ // +@description('Required. Name of the Deployment Script.') +@maxLength(24) +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Required. Specifies the Kind of the Deployment Script.') +@allowed([ + 'AzureCLI' + 'AzurePowerShell' +]) +param kind string + +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType + +@description('Optional. Resource tags.') +param tags object? + +@description('Optional. Azure PowerShell module version to be used. See a list of supported Azure PowerShell versions: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list.') +param azPowerShellVersion string? + +@description('Optional. Azure CLI module version to be used. See a list of supported Azure CLI versions: https://mcr.microsoft.com/v2/azure-cli/tags/list.') +param azCliVersion string? + +@description('Optional. Script body. Max length: 32000 characters. To run an external script, use primaryScriptURI instead.') +param scriptContent string? + +@description('Optional. Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent instead.') +param primaryScriptUri string? + +@metadata({ + example: ''' +secureList: [ + { + name: 'string' + secureValue: 'string' + value: 'string' + } +] +''' +}) +@description('Optional. The environment variables to pass over to the script. The list is passed as an object with a key name "secureList" and the value is the list of environment variables (array). The list must have a \'name\' and a \'value\' or a \'secretValue\' property for each object.') +@secure() +param environmentVariables object = {} + +@description('Optional. List of supporting files for the external script (defined in primaryScriptUri). Does not work with internal scripts (code defined in scriptContent).') +param supportingScriptUris array? + +@description('Optional. List of subnet IDs to use for the container group. This is required if you want to run the deployment script in a private network.') +param subnetResourceIds string[]? + +@description('Optional. Command-line arguments to pass to the script. Arguments are separated by spaces.') +param arguments string? + +@description('Optional. Interval for which the service retains the script resource after it reaches a terminal state. Resource will be deleted when this duration expires. Duration is based on ISO 8601 pattern (for example P7D means one week).') +param retentionInterval string? + +@description('Generated. Do not provide a value! This date value is used to make sure the script run every time the template is deployed.') +param baseTime string = utcNow('yyyy-MM-dd-HH-mm-ss') + +@description('Optional. When set to false, script will run every time the template is deployed. When set to true, the script will only run once.') +param runOnce bool = false + +@description('Optional. The clean up preference when the script execution gets in a terminal state. Specify the preference on when to delete the deployment script resources. The default value is Always, which means the deployment script resources are deleted despite the terminal state (Succeeded, Failed, canceled).') +@allowed([ + 'Always' + 'OnSuccess' + 'OnExpiration' +]) +param cleanupPreference string = 'Always' + +@description('Optional. Container group name, if not specified then the name will get auto-generated. Not specifying a \'containerGroupName\' indicates the system to generate a unique name which might end up flagging an Azure Policy as non-compliant. Use \'containerGroupName\' when you have an Azure Policy that expects a specific naming convention or when you want to fully control the name. \'containerGroupName\' property must be between 1 and 63 characters long, must contain only lowercase letters, numbers, and dashes and it cannot start or end with a dash and consecutive dashes are not allowed.') +param containerGroupName string? + +@description('Optional. The resource ID of the storage account to use for this deployment script. If none is provided, the deployment script uses a temporary, managed storage account.') +param storageAccountResourceId string = '' + +@description('Optional. Maximum allowed script execution time specified in ISO 8601 format. Default value is PT1H - 1 hour; \'PT30M\' - 30 minutes; \'P5D\' - 5 days; \'P1Y\' 1 year.') +param timeout string? + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// =========== // +// Variables // +// =========== // + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + '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') +} + +var subnetIds = [for subnetResourceId in (subnetResourceIds ?? []): { + id: subnetResourceId +}] + +var containerSettings = { + containerGroupName: containerGroupName + subnetIds: !empty(subnetIds ?? []) ? subnetIds : null +} + +var formattedUserAssignedIdentities = reduce(map((managedIdentities.?userAssignedResourcesIds ?? []), (id) => { '${id}': {} }), {}, (cur, next) => union(cur, next)) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) ? { + type: !empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null +} : null + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-04-01' existing = if (!empty(storageAccountResourceId)) { + name: last(split((!empty(storageAccountResourceId) ? storageAccountResourceId : 'dummyAccount'), '/'))! + scope: resourceGroup(split((!empty(storageAccountResourceId) ? storageAccountResourceId : '//'), '/')[2], split((!empty(storageAccountResourceId) ? storageAccountResourceId : '////'), '/')[4]) +} + +var storageAccountSettings = !empty(storageAccountResourceId) ? { + storageAccountKey: listKeys(storageAccount.id, '2023-01-01').keys[0].value + storageAccountName: last(split(storageAccountResourceId, '/')) +} : null + +// ============ // +// Dependencies // +// ============ // + +resource deploymentScript_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' ? 'Cannot delete resource or child resources.' : 'Cannot delete or modify the resource or child resources.' + } + scope: deploymentScript +} + +resource deploymentScript_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { + name: guid(deploymentScript.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) + properties: { + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: deploymentScript +}] + +resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: '46d3xbcp.res.resources-deploymentscript.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +// ================ // +// Resources // +// ================ // + +resource deploymentScript 'Microsoft.Resources/deploymentScripts@2023-08-01' = { + name: name + location: location + tags: tags + identity: identity + kind: any(kind) + properties: { + azPowerShellVersion: kind == 'AzurePowerShell' ? azPowerShellVersion : null + azCliVersion: kind == 'AzureCLI' ? azCliVersion : null + containerSettings: !empty(containerSettings) ? containerSettings : null + storageAccountSettings: !empty(storageAccountResourceId) ? storageAccountSettings : null + arguments: arguments + environmentVariables: !empty(environmentVariables) ? environmentVariables.secureList : [] + scriptContent: !empty(scriptContent) ? scriptContent : null + primaryScriptUri: !empty(primaryScriptUri) ? primaryScriptUri : null + supportingScriptUris: !empty(supportingScriptUris) ? supportingScriptUris : null + cleanupPreference: cleanupPreference + forceUpdateTag: runOnce ? resourceGroup().name : baseTime + retentionInterval: retentionInterval + timeout: timeout + } +} + +// ================ // +// Outputs // +// ================ // + +@description('The resource ID of the deployment script.') +output resourceId string = deploymentScript.id + +@description('The resource group the deployment script was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the deployment script.') +output name string = deploymentScript.name + +@description('The location the resource was deployed into.') +output location string = deploymentScript.location + +@description('The output of the deployment script.') +output outputs object = contains(deploymentScript.properties, 'outputs') ? deploymentScript.properties.outputs : {} + +// ================ // +// Definitions // +// ================ // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type managedIdentitiesType = { + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourcesIds: string[] +}? + +type roleAssignmentType = { + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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"') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/res/resources/deployment-script/main.json b/avm/res/resources/deployment-script/main.json new file mode 100644 index 0000000000..aad829ed7c --- /dev/null +++ b/avm/res/resources/deployment-script/main.json @@ -0,0 +1,450 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "18060507539317064739" + }, + "name": "Deployment Scripts", + "description": "This module deploys Deployment Scripts.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourcesIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Name of the Deployment Script." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "AzureCLI", + "AzurePowerShell" + ], + "metadata": { + "description": "Required. Specifies the Kind of the Deployment Script." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "azPowerShellVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Azure PowerShell module version to be used. See a list of supported Azure PowerShell versions: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list." + } + }, + "azCliVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Azure CLI module version to be used. See a list of supported Azure CLI versions: https://mcr.microsoft.com/v2/azure-cli/tags/list." + } + }, + "scriptContent": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Script body. Max length: 32000 characters. To run an external script, use primaryScriptURI instead." + } + }, + "primaryScriptUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent instead." + } + }, + "environmentVariables": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "example": "secureList: [\n {\n name: 'string'\n secureValue: 'string'\n value: 'string'\n }\n]\n", + "description": "Optional. The environment variables to pass over to the script. The list is passed as an object with a key name \"secureList\" and the value is the list of environment variables (array). The list must have a 'name' and a 'value' or a 'secretValue' property for each object." + } + }, + "supportingScriptUris": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of supporting files for the external script (defined in primaryScriptUri). Does not work with internal scripts (code defined in scriptContent)." + } + }, + "subnetResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of subnet IDs to use for the container group. This is required if you want to run the deployment script in a private network." + } + }, + "arguments": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Command-line arguments to pass to the script. Arguments are separated by spaces." + } + }, + "retentionInterval": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Interval for which the service retains the script resource after it reaches a terminal state. Resource will be deleted when this duration expires. Duration is based on ISO 8601 pattern (for example P7D means one week)." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('yyyy-MM-dd-HH-mm-ss')]", + "metadata": { + "description": "Generated. Do not provide a value! This date value is used to make sure the script run every time the template is deployed." + } + }, + "runOnce": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When set to false, script will run every time the template is deployed. When set to true, the script will only run once." + } + }, + "cleanupPreference": { + "type": "string", + "defaultValue": "Always", + "allowedValues": [ + "Always", + "OnSuccess", + "OnExpiration" + ], + "metadata": { + "description": "Optional. The clean up preference when the script execution gets in a terminal state. Specify the preference on when to delete the deployment script resources. The default value is Always, which means the deployment script resources are deleted despite the terminal state (Succeeded, Failed, canceled)." + } + }, + "containerGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Container group name, if not specified then the name will get auto-generated. Not specifying a 'containerGroupName' indicates the system to generate a unique name which might end up flagging an Azure Policy as non-compliant. Use 'containerGroupName' when you have an Azure Policy that expects a specific naming convention or when you want to fully control the name. 'containerGroupName' property must be between 1 and 63 characters long, must contain only lowercase letters, numbers, and dashes and it cannot start or end with a dash and consecutive dashes are not allowed." + } + }, + "storageAccountResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the storage account to use for this deployment script. If none is provided, the deployment script uses a temporary, managed storage account." + } + }, + "timeout": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Maximum allowed script execution time specified in ISO 8601 format. Default value is PT1H - 1 hour; 'PT30M' - 30 minutes; 'P5D' - 5 days; 'P1Y' 1 year." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "subnetIds", + "count": "[length(coalesce(parameters('subnetResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('subnetResourceIds'), createArray())[copyIndex('subnetIds')]]" + } + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + }, + "containerSettings": { + "containerGroupName": "[parameters('containerGroupName')]", + "subnetIds": "[if(not(empty(coalesce(variables('subnetIds'), createArray()))), variables('subnetIds'), null())]" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), createObject()))), 'UserAssigned', null()), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "storageAccount": { + "condition": "[not(empty(parameters('storageAccountResourceId')))]", + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "subscriptionId": "[split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '////'), '/')[4]]", + "name": "[last(split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), 'dummyAccount'), '/'))]" + }, + "deploymentScript_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Resources/deploymentScripts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "deploymentScript" + ] + }, + "deploymentScript_roleAssignments": { + "copy": { + "name": "deploymentScript_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Resources/deploymentScripts/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Resources/deploymentScripts', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "deploymentScript" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.resources-deploymentscript.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "deploymentScript": { + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2023-08-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "kind": "[parameters('kind')]", + "properties": { + "azPowerShellVersion": "[if(equals(parameters('kind'), 'AzurePowerShell'), parameters('azPowerShellVersion'), null())]", + "azCliVersion": "[if(equals(parameters('kind'), 'AzureCLI'), parameters('azCliVersion'), null())]", + "containerSettings": "[if(not(empty(variables('containerSettings'))), variables('containerSettings'), null())]", + "storageAccountSettings": "[if(not(empty(parameters('storageAccountResourceId'))), if(not(empty(parameters('storageAccountResourceId'))), createObject('storageAccountKey', listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '//'), '/')[2], split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), 'dummyAccount'), '/'))), '2023-01-01').keys[0].value, 'storageAccountName', last(split(parameters('storageAccountResourceId'), '/'))), null()), null())]", + "arguments": "[parameters('arguments')]", + "environmentVariables": "[if(not(empty(parameters('environmentVariables'))), parameters('environmentVariables').secureList, createArray())]", + "scriptContent": "[if(not(empty(parameters('scriptContent'))), parameters('scriptContent'), null())]", + "primaryScriptUri": "[if(not(empty(parameters('primaryScriptUri'))), parameters('primaryScriptUri'), null())]", + "supportingScriptUris": "[if(not(empty(parameters('supportingScriptUris'))), parameters('supportingScriptUris'), null())]", + "cleanupPreference": "[parameters('cleanupPreference')]", + "forceUpdateTag": "[if(parameters('runOnce'), resourceGroup().name, parameters('baseTime'))]", + "retentionInterval": "[parameters('retentionInterval')]", + "timeout": "[parameters('timeout')]" + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployment script." + }, + "value": "[resourceId('Microsoft.Resources/deploymentScripts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the deployment script was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployment script." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('deploymentScript', '2023-08-01', 'full').location]" + }, + "outputs": { + "type": "object", + "metadata": { + "description": "The output of the deployment script." + }, + "value": "[if(contains(reference('deploymentScript'), 'outputs'), reference('deploymentScript').outputs, createObject())]" + } + } +} \ No newline at end of file diff --git a/avm/res/resources/deployment-script/tests/e2e/cli/dependencies.bicep b/avm/res/resources/deployment-script/tests/e2e/cli/dependencies.bicep new file mode 100644 index 0000000000..d49ed08f87 --- /dev/null +++ b/avm/res/resources/deployment-script/tests/e2e/cli/dependencies.bicep @@ -0,0 +1,31 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + supportsHttpsTrafficOnly: true + } +} + +@description('The resource ID of the created managed identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created storage account.') +output storageAccountResourceId string = storageAccount.id diff --git a/avm/res/resources/deployment-script/tests/e2e/cli/main.test.bicep b/avm/res/resources/deployment-script/tests/e2e/cli/main.test.bicep new file mode 100644 index 0000000000..36a1b7056f --- /dev/null +++ b/avm/res/resources/deployment-script/tests/e2e/cli/main.test.bicep @@ -0,0 +1,73 @@ +targetScope = 'subscription' + +metadata name = 'Using Azure CLI' +metadata description = 'This instance deploys the module with an Azure CLI script.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'avm-${namePrefix}-resources.deploymentscripts-${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 = 'rdscli' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}st${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + azCliVersion: '2.9.1' + kind: 'AzureCLI' + retentionInterval: 'P1D' + environmentVariables: { + secureList: [ + { + name: 'var1' + value: 'AVM Deployment Script test!' + } + ] + } + scriptContent: 'echo \'Enviornment variable value is: \' $var1' + storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + } +} diff --git a/avm/res/resources/deployment-script/tests/e2e/defaults/dependencies.bicep b/avm/res/resources/deployment-script/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 0000000000..d49ed08f87 --- /dev/null +++ b/avm/res/resources/deployment-script/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,31 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + supportsHttpsTrafficOnly: true + } +} + +@description('The resource ID of the created managed identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created storage account.') +output storageAccountResourceId string = storageAccount.id diff --git a/avm/res/resources/deployment-script/tests/e2e/defaults/main.test.bicep b/avm/res/resources/deployment-script/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..926bc535be --- /dev/null +++ b/avm/res/resources/deployment-script/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,68 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = ''' +This instance deploys the module with the minimum set of required parameters. +> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. +''' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'avm-${namePrefix}-resources.deploymentscripts-${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 = 'rdsmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}st${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + azPowerShellVersion: '9.7' + kind: 'AzurePowerShell' + retentionInterval: 'P1D' + scriptContent: 'Write-Host \'AVM Deployment Script test!\'' + storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + } +} diff --git a/avm/res/resources/deployment-script/tests/e2e/max/dependencies.bicep b/avm/res/resources/deployment-script/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..09a469b844 --- /dev/null +++ b/avm/res/resources/deployment-script/tests/e2e/max/dependencies.bicep @@ -0,0 +1,33 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + supportsHttpsTrafficOnly: true + } +} +@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 storage account.') +output storageAccountResourceId string = storageAccount.id diff --git a/avm/res/resources/deployment-script/tests/e2e/max/main.test.bicep b/avm/res/resources/deployment-script/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..436e0d8bfa --- /dev/null +++ b/avm/res/resources/deployment-script/tests/e2e/max/main.test.bicep @@ -0,0 +1,107 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'avm-${namePrefix}-resources.deploymentscripts-${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 = 'rdsmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}st${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + azCliVersion: '2.9.1' + kind: 'AzureCLI' + retentionInterval: 'P1D' + cleanupPreference: 'Always' + lock: { + kind: 'None' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + containerGroupName: 'dep-${namePrefix}-cg-${serviceShort}' + arguments: '-argument1 \\"test\\"' + environmentVariables: { + secureList: [ + { + name: 'var1' + value: 'test' + } + { + name: 'var2' + secureValue: guid(deployment().name) + } + ] + } + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + timeout: 'PT1H' + runOnce: true + scriptContent: 'echo \'AVM Deployment Script test!\'' + storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId + } +} diff --git a/avm/res/resources/deployment-script/tests/e2e/private-network/dependencies.bicep b/avm/res/resources/deployment-script/tests/e2e/private-network/dependencies.bicep new file mode 100644 index 0000000000..6d0153f7ca --- /dev/null +++ b/avm/res/resources/deployment-script/tests/e2e/private-network/dependencies.bicep @@ -0,0 +1,102 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +var addressPrefix = '10.0.0.0/16' + +// Role required for deployment script to be able to use a storage account via private networking +resource storageFileDataPrivilegedContributor 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: '69566ab7-960f-475b-8e7c-b3118f30c6bd' + scope: tenant() +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storagePermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('storageFileDataPrivilegedContributorRole', managedIdentity.id, storageAccount.id) + scope: storageAccount + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: storageFileDataPrivilegedContributor.id + principalType: 'ServicePrincipal' + } +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + supportsHttpsTrafficOnly: true + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + virtualNetworkRules: [ + { + id: virtualNetwork.properties.subnets[0].id + action: 'Allow' + state: 'Succeeded' + } + ] + } + } +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + ] + delegations: [ + { + name: 'Microsoft.ContainerInstance.containerGroups' + properties: { + serviceName: 'Microsoft.ContainerInstance/containerGroups' + } + } + ] + } + } + ] + } +} + +@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 storage account.') +output storageAccountResourceId string = storageAccount.id + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/avm/res/resources/deployment-script/tests/e2e/private-network/main.test.bicep b/avm/res/resources/deployment-script/tests/e2e/private-network/main.test.bicep new file mode 100644 index 0000000000..552dad3ce5 --- /dev/null +++ b/avm/res/resources/deployment-script/tests/e2e/private-network/main.test.bicep @@ -0,0 +1,72 @@ +targetScope = 'subscription' + +metadata name = 'Using Private Networking' +metadata description = 'This instance deploys the module with access to a private network.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'avm-${namePrefix}-resources.deploymentscripts-${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 = 'rdsnet' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}st${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + azCliVersion: '2.9.1' + kind: 'AzureCLI' + retentionInterval: 'P1D' + cleanupPreference: 'Always' + subnetResourceIds: [ + nestedDependencies.outputs.subnetResourceId + ] + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + timeout: 'PT1H' + runOnce: true + scriptContent: 'echo \'AVM Deployment Script test!\'' + storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId + } +} diff --git a/avm/res/resources/deployment-script/tests/e2e/ps/dependencies.bicep b/avm/res/resources/deployment-script/tests/e2e/ps/dependencies.bicep new file mode 100644 index 0000000000..d49ed08f87 --- /dev/null +++ b/avm/res/resources/deployment-script/tests/e2e/ps/dependencies.bicep @@ -0,0 +1,31 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + supportsHttpsTrafficOnly: true + } +} + +@description('The resource ID of the created managed identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created storage account.') +output storageAccountResourceId string = storageAccount.id diff --git a/avm/res/resources/deployment-script/tests/e2e/ps/main.test.bicep b/avm/res/resources/deployment-script/tests/e2e/ps/main.test.bicep new file mode 100644 index 0000000000..20951e15ae --- /dev/null +++ b/avm/res/resources/deployment-script/tests/e2e/ps/main.test.bicep @@ -0,0 +1,66 @@ +targetScope = 'subscription' + +metadata name = 'Using Azure PowerShell' +metadata description = 'This instance deploys the module with an Azure PowerShell script.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'avm-${namePrefix}-resources.deploymentscripts-${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 = 'rdsps' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}st${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + azPowerShellVersion: '9.7' + kind: 'AzurePowerShell' + retentionInterval: 'P1D' + arguments: '-var1 \\"AVM Deployment Script test!\\"' + scriptContent: 'param([string] $var1);Write-Host \'Argument var1 value is:\' $var1' + storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + } +} diff --git a/avm/res/resources/deployment-script/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/resources/deployment-script/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 0000000000..079914d477 --- /dev/null +++ b/avm/res/resources/deployment-script/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,38 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + supportsHttpsTrafficOnly: true + allowBlobPublicAccess: false + minimumTlsVersion: 'TLS1_2' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } +} + +@description('The resource ID of the created managed identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created storage account.') +output storageAccountResourceId string = storageAccount.id diff --git a/avm/res/resources/deployment-script/tests/e2e/waf-aligned/main.test.bicep b/avm/res/resources/deployment-script/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..3f0dd98b31 --- /dev/null +++ b/avm/res/resources/deployment-script/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,80 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'avm-${namePrefix}-resources.deploymentscripts-${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 = 'rdswaf' + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableTelemetry bool = true + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}st${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + enableTelemetry: enableTelemetry + name: '${namePrefix}${serviceShort}001' + location: location + azCliVersion: '2.9.1' + kind: 'AzureCLI' + retentionInterval: 'P1D' + cleanupPreference: 'Always' + lock: { + kind: 'None' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + timeout: 'PT1H' + runOnce: true + scriptContent: 'echo \'AVM Deployment Script test!\'' + storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + } +} diff --git a/avm/res/resources/deployment-script/version.json b/avm/res/resources/deployment-script/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/res/resources/deployment-script/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From 3a0f5a63201bc4b9884b529b950b9f56c816282f Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Thu, 30 Nov 2023 11:23:38 +0100 Subject: [PATCH 17/22] feat: Added `WhatIf` support to `Test-ModuleLocally` script + several smaller bugfixes (#679) ## Description - Added WhatIf capabilities as per PR: https://github.com/Azure/ResourceModules/pull/4241 - Small fixes in `Test-ModuleLocally` script - Removed support for JSON parameter files from `Test-ModuleLocally` script - Updated naming of `Test-Deployment` script to not depend on `Microsoft.` prefix --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .../Test-TemplateDeployment.ps1 | 37 ++-- avm/utilities/tools/Test-ModuleLocally.ps1 | 100 ++++----- .../helper/Get-TemplateDeploymentWhatIf.ps1 | 192 ++++++++++++++++++ 3 files changed, 248 insertions(+), 81 deletions(-) create mode 100644 avm/utilities/tools/helper/Get-TemplateDeploymentWhatIf.ps1 diff --git a/avm/utilities/pipelines/e2eValidation/resourceDeployment/Test-TemplateDeployment.ps1 b/avm/utilities/pipelines/e2eValidation/resourceDeployment/Test-TemplateDeployment.ps1 index 581d9f6da9..240145fbb0 100644 --- a/avm/utilities/pipelines/e2eValidation/resourceDeployment/Test-TemplateDeployment.ps1 +++ b/avm/utilities/pipelines/e2eValidation/resourceDeployment/Test-TemplateDeployment.ps1 @@ -85,6 +85,25 @@ function Test-TemplateDeployment { } process { + $deploymentNamePrefix = Split-Path -Path (Split-Path $templateFilePath -Parent) -LeafBase + if ([String]::IsNullOrEmpty($deploymentNamePrefix)) { + $deploymentNamePrefix = 'templateDeployment-{0}' -f (Split-Path $templateFilePath -LeafBase) + } + + # Convert, e.g., [C:\myFork\avm\res\kubernetes-configuration\flux-configuration\tests\e2e\defaults\main.test.bicep] to [a-r-kc-fc-defaults] + $shortPathElems = ((Split-Path $templateFilePath) -replace ('{0}[\\|\/]' -f [regex]::Escape($repoRoot))) -split '[\\|\/]' | Where-Object { $_ -notin @('tests', 'e2e') } + # Shorten all elements but the last + $reducedElem = $shortPathElems[0 .. ($shortPathElems.Count - 2)] | ForEach-Object { + $shortPathElem = $_ + if ($shortPathElem -match '-') { + ($shortPathElem -split '-' | ForEach-Object { $_[0] }) -join '' + } else { + $shortPathElem[0] + } + } + # Add the last back and join the elements together + $deploymentNamePrefix = ($reducedElem + @($shortPathElems[-1])) -join '-' + $DeploymentInputs = @{ TemplateFile = $templateFilePath Verbose = $true @@ -102,24 +121,6 @@ function Test-TemplateDeployment { $deploymentScope = Get-ScopeOfTemplateFile -TemplateFilePath $templateFilePath -Verbose - $deploymentNamePrefix = Split-Path -Path (Split-Path $templateFilePath -Parent) -LeafBase - if ([String]::IsNullOrEmpty($deploymentNamePrefix)) { - $deploymentNamePrefix = 'templateDeployment-{0}' -f (Split-Path $templateFilePath -LeafBase) - } - if ($templateFilePath -match '.*(\\|\/)Microsoft.+') { - # If we can assume we're operating in a module structure, we can further fetch the provider namespace & resource type - $shortPathElem = (($templateFilePath -split 'Microsoft\.')[1] -replace '\\', '/') -split '/' # e.g., AppConfiguration, configurationStores, .test, common, main.test.bicep - $providerNamespace = $shortPathElem[0] # e.g., AppConfiguration - $providerNamespaceShort = ($providerNamespace -creplace '[^A-Z]').ToLower() # e.g., ac - - $resourceType = $shortPathElem[1] # e.g., configurationStores - $resourceTypeShort = ('{0}{1}' -f ($resourceType.ToLower())[0], ($resourceType -creplace '[^A-Z]')).ToLower() # e.g. cs - - $testFolderShort = Split-Path (Split-Path $templateFilePath -Parent) -Leaf # e.g., common - - $deploymentNamePrefix = "$providerNamespaceShort-$resourceTypeShort-$testFolderShort" # e.g., ac-cs-common - } - # Generate a valid deployment name. Must match ^[-\w\._\(\)]+$ do { $deploymentName = ('{0}-{1}' -f $deploymentNamePrefix, (Get-Date -Format 'yyyyMMddTHHMMssffffZ'))[0..63] -join '' diff --git a/avm/utilities/tools/Test-ModuleLocally.ps1 b/avm/utilities/tools/Test-ModuleLocally.ps1 index d2a5f612f9..440cf92bbb 100644 --- a/avm/utilities/tools/Test-ModuleLocally.ps1 +++ b/avm/utilities/tools/Test-ModuleLocally.ps1 @@ -37,7 +37,7 @@ Optional. A hashtable parameter that contains custom tokens to be replaced in th $TestModuleLocallyInput = @{ TemplateFilePath = 'C:\network\route-table\main.bicep' - ModuleTestFilePath = 'C:\network\route-table\.test\parameters.json' + ModuleTestFilePath = 'C:\network\route-table\.test\common\main.test.bicep' PesterTest = $false DeploymentTest = $false ValidationTest = $true @@ -56,46 +56,26 @@ $TestModuleLocallyInput = @{ } Test-ModuleLocally @TestModuleLocallyInput -Verbose -Run a Test-Az*Deployment using a specific parameter-template combination with the provided tokens +Run a Test-Az*Deployment using a test file with the provided tokens .EXAMPLE $TestModuleLocallyInput = @{ TemplateFilePath = 'C:\network\route-table\main.bicep' - ModuleTestFilePath = 'C:\network\route-table\.test\common\main.test.bicep' - PesterTest = $false - DeploymentTest = $false - ValidationTest = $true - ValidateOrDeployParameters = @{ - Location = 'westeurope' - ResourceGroupName = 'validation-rg' - SubscriptionId = '00000000-0000-0000-0000-000000000000' - ManagementGroupId = '00000000-0000-0000-0000-000000000000' - RemoveDeployment = $false - } - AdditionalTokens = @{ - tenantId = '00000000-0000-0000-0000-000000000000' - namePrefix = 'avm' - moduleVersion = '1.0.0' - } + PesterTest = $true } Test-ModuleLocally @TestModuleLocallyInput -Verbose -Run a Test-Az*Deployment using a test file with the provided tokens +Run all Pester tests for the given template file .EXAMPLE $TestModuleLocallyInput = @{ TemplateFilePath = 'C:\network\route-table\main.bicep' PesterTest = $true - DeploymentTest = $false - ValidationTest = $true ValidateOrDeployParameters = @{ - Location = 'westeurope' - ResourceGroupName = 'validation-rg' SubscriptionId = '00000000-0000-0000-0000-000000000000' ManagementGroupId = '00000000-0000-0000-0000-000000000000' - RemoveDeployment = $false } AdditionalTokens = @{ tenantId = '00000000-0000-0000-0000-000000000000' @@ -105,40 +85,33 @@ $TestModuleLocallyInput = @{ } Test-ModuleLocally @TestModuleLocallyInput -Verbose -Run all Pester tests for a given template and a Test-Az*Deployment using each test file in the module's default test folder ('.test') in combination with the template and the provided tokens - -.EXAMPLE - -$TestModuleLocallyInput = @{ - TemplateFilePath = 'C:\network\route-table\main.bicep' - PesterTest = $true -} -Test-ModuleLocally @TestModuleLocallyInput -Verbose - -Run all Pester tests for the given template file +Run all Pester tests for the given template file including tests for the use of tokens .EXAMPLE - $TestModuleLocallyInput = @{ TemplateFilePath = 'C:\network\route-table\main.bicep' - PesterTest = $true + ModuleTestFilePath = 'C:\network\route-table\.test\common\main.test.bicep' + PesterTest = $false + DeploymentTest = $false + WhatIfTest = $true + ValidationTest = $false ValidateOrDeployParameters = @{ + Location = 'westeurope' + ResourceGroupName = 'validation-rg' SubscriptionId = '00000000-0000-0000-0000-000000000000' ManagementGroupId = '00000000-0000-0000-0000-000000000000' + RemoveDeployment = $false } AdditionalTokens = @{ - tenantId = '00000000-0000-0000-0000-000000000000' - namePrefix = 'avm' - moduleVersion = '1.0.0' + tenantId = '00000000-0000-0000-0000-000000000000' } } Test-ModuleLocally @TestModuleLocallyInput -Verbose - -Run all Pester tests for the given template file including tests for the use of tokens +Get What-If deployment result using a test file with the provided tokens .NOTES - Make sure you provide the right information in the 'ValidateOrDeployParameters' parameter for this function to work. -- Ensure you have the ability to perform the deployment operations using your account (if planning to test deploy) +- Ensure you have the ability to perform the deployment operations using your account (if planning to test deploy or performing what-if validation.) #> function Test-ModuleLocally { @@ -148,7 +121,7 @@ function Test-ModuleLocally { [string] $TemplateFilePath, [Parameter(Mandatory = $false)] - [string] $ModuleTestFilePath = (Join-Path (Split-Path $TemplateFilePath -Parent) '.test'), + [string] $ModuleTestFilePath = (Join-Path (Split-Path $TemplateFilePath -Parent) 'tests'), [Parameter(Mandatory = $false)] [string] $PesterTestFilePath = 'avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1', @@ -169,7 +142,10 @@ function Test-ModuleLocally { [switch] $DeploymentTest, [Parameter(Mandatory = $false)] - [switch] $ValidationTest + [switch] $ValidationTest, + + [Parameter(Mandatory = $false)] + [switch] $WhatIfTest ) begin { @@ -183,6 +159,7 @@ function Test-ModuleLocally { # Load Modules Validation / Deployment Scripts . (Join-Path $utilitiesFolderPath 'pipelines' 'e2eValidation' 'resourceDeployment' 'New-TemplateDeployment.ps1') . (Join-Path $utilitiesFolderPath 'pipelines' 'e2eValidation' 'resourceDeployment' 'Test-TemplateDeployment.ps1') + . (Join-Path $PSScriptRoot 'helper' 'Get-TemplateDeploymentWhatIf.ps1') } process { @@ -247,7 +224,7 @@ function Test-ModuleLocally { # Validation & Deployment tests # ################################# - if (($ValidationTest -or $DeploymentTest) -and $ValidateOrDeployParameters) { + if (($ValidationTest -or $DeploymentTest -or $WhatIfTest) -and $ValidateOrDeployParameters) { # Invoke Token Replacement Functionality and Convert Tokens in Parameter Files $null = Convert-TokensInFileList @tokenConfiguration @@ -255,13 +232,12 @@ function Test-ModuleLocally { # Deployment & Validation Testing # ------------------------------- $functionInput = @{ - TemplateFilePath = $TemplateFilePath location = $ValidateOrDeployParameters.Location resourceGroupName = $ValidateOrDeployParameters.ResourceGroupName subscriptionId = $ValidateOrDeployParameters.SubscriptionId managementGroupId = $ValidateOrDeployParameters.ManagementGroupId additionalParameters = $additionalParameters - RepoRoot = Split-Path (Split-Path (Split-Path $PSScriptRoot)) + RepoRoot = $repoRootPath Verbose = $true } @@ -272,12 +248,17 @@ function Test-ModuleLocally { # Loop through test files foreach ($moduleTestFile in $moduleTestFiles) { Write-Verbose ('Validating module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)) -Verbose - if ((Split-Path $moduleTestFile -Extension) -eq '.json') { - Test-TemplateDeployment @functionInput -ParameterFilePath $moduleTestFile - } else { - $functionInput['TemplateFilePath'] = $moduleTestFile - Test-TemplateDeployment @functionInput - } + Test-TemplateDeployment @functionInput -TemplateFilePath $moduleTestFile + } + } + + # What-If validation for template + # ----------------- + if ($WhatIfTest) { + # Loop through test files + foreach ($moduleTestFile in $moduleTestFiles) { + Write-Verbose ('Get Deployment What-If result for module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)) -Verbose + Get-TemplateDeploymentWhatIf @functionInput -TemplateFilePath $moduleTestFile } } @@ -288,15 +269,8 @@ function Test-ModuleLocally { # Loop through test files foreach ($moduleTestFile in $moduleTestFiles) { Write-Verbose ('Deploy Module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)) -Verbose - if ((Split-Path $moduleTestFile -Extension) -eq '.json') { - if ($PSCmdlet.ShouldProcess(('Module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)), 'Deploy')) { - New-TemplateDeployment @functionInput -ParameterFilePath $moduleTestFile - } - } else { - $functionInput['TemplateFilePath'] = $moduleTestFile - if ($PSCmdlet.ShouldProcess(('Module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)), 'Deploy')) { - New-TemplateDeployment @functionInput - } + if ($PSCmdlet.ShouldProcess(('Module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)), 'Deploy')) { + New-TemplateDeployment @functionInput -TemplateFilePath $moduleTestFile } } } diff --git a/avm/utilities/tools/helper/Get-TemplateDeploymentWhatIf.ps1 b/avm/utilities/tools/helper/Get-TemplateDeploymentWhatIf.ps1 new file mode 100644 index 0000000000..ff8dc1a960 --- /dev/null +++ b/avm/utilities/tools/helper/Get-TemplateDeploymentWhatIf.ps1 @@ -0,0 +1,192 @@ +<# +.SYNOPSIS +Get a template What-If deployment result using a given parameter file + +.DESCRIPTION +Get a template What-If deployment resultusing a given parameter file +Works on a resource group, subscription, managementgroup and tenant level + +.PARAMETER parametersBasePath +Mandatory. The path to the root of the parameters folder to test with + +.PARAMETER templateFilePath +Mandatory. Path to the template file from root. + +.PARAMETER parameterFilePath +Optional. Path to the parameter file from root. + +.PARAMETER location +Mandatory. Location to test in. E.g. WestEurope + +.PARAMETER resourceGroupName +Optional. Name of the resource group to deploy into. Mandatory if deploying into a resource group (resource group level) + +.PARAMETER subscriptionId +Optional. ID of the subscription to deploy into. Mandatory if deploying into a subscription (subscription level) using a Management groups service connection + +.PARAMETER managementGroupId +Optional. Name of the management group to deploy into. Mandatory if deploying into a management group (management group level) + +.PARAMETER additionalParameters +Optional. Additional parameters you can provide with the deployment. E.g. @{ resourceGroupName = 'myResourceGroup' } + +.PARAMETER RepoRoot +Optional. The path to the repository's root + +.EXAMPLE +Get-TemplateDeploymentWhatIf -templateFilePath 'C:/key-vault/vault/main.bicep' -parameterFilePath 'C:/key-vault/vault/.test/parameters.json' -location 'WestEurope' -resourceGroupName 'aLegendaryRg' + +Get What-If deployment result for the main.bicep of the KeyVault module with the parameter file 'parameters.json' using the resource group 'aLegendaryRg' in location 'WestEurope' + +.EXAMPLE +Get-TemplateDeploymentWhatIf -templateFilePath 'C:/key-vault/vault/main.bicep' -location 'WestEurope' -resourceGroupName 'aLegendaryRg' + +Get What-If deployment result for the main.bicep of the KeyVault module using the resource group 'aLegendaryRg' in location 'WestEurope' + +.EXAMPLE +Get-TemplateDeploymentWhatIf -templateFilePath 'C:/resources/resource-group/main.json' -parameterFilePath 'C:/resources/resource-group/.test/parameters.json' -location 'WestEurope' + +Get What-If deployment result for the main.json of the ResourceGroup module with the parameter file 'parameters.json' in location 'WestEurope' +#> +function Get-TemplateDeploymentWhatIf { + + [CmdletBinding(SupportsShouldProcess)] + param ( + [Parameter(Mandatory)] + [string] $templateFilePath, + + [Parameter(Mandatory)] + [string] $location, + + [Parameter(Mandatory = $false)] + [string] $parameterFilePath, + + [Parameter(Mandatory = $false)] + [string] $resourceGroupName, + + [Parameter(Mandatory = $false)] + [string] $subscriptionId, + + [Parameter(Mandatory = $false)] + [string] $managementGroupId, + + [Parameter(Mandatory = $false)] + [Hashtable] $additionalParameters, + + [Parameter(Mandatory = $false)] + [string] $RepoRoot = (Get-Item -Path $PSScriptRoot).parent.parent.parent.parent.FullName + ) + + begin { + Write-Debug ('{0} entered' -f $MyInvocation.MyCommand) + + # Load helper + . (Join-Path $RepoRoot 'avm' 'utilities' 'pipelines' 'sharedScripts' 'Get-ScopeOfTemplateFile.ps1') + } + + process { + $deploymentNamePrefix = Split-Path -Path (Split-Path $templateFilePath -Parent) -LeafBase + if ([String]::IsNullOrEmpty($deploymentNamePrefix)) { + $deploymentNamePrefix = 'templateDeployment-{0}' -f (Split-Path $templateFilePath -LeafBase) + } + + # Convert, e.g., [C:\myFork\avm\res\kubernetes-configuration\flux-configuration\tests\e2e\defaults\main.test.bicep] to [a-r-kc-fc-defaults] + $shortPathElems = ((Split-Path $templateFilePath) -replace ('{0}[\\|\/]' -f [regex]::Escape($repoRoot))) -split '[\\|\/]' | Where-Object { $_ -notin @('tests', 'e2e') } + # Shorten all elements but the last + $reducedElem = $shortPathElems[0 .. ($shortPathElems.Count - 2)] | ForEach-Object { + $shortPathElem = $_ + if ($shortPathElem -match '-') { + ($shortPathElem -split '-' | ForEach-Object { $_[0] }) -join '' + } else { + $shortPathElem[0] + } + } + # Add the last back and join the elements together + $deploymentNamePrefix = ($reducedElem + @($shortPathElems[-1])) -join '-' + + $DeploymentInputs = @{ + TemplateFile = $templateFilePath + Verbose = $true + OutVariable = 'ValidationErrors' + } + if (-not [String]::IsNullOrEmpty($parameterFilePath)) { + $DeploymentInputs['TemplateParameterFile'] = $parameterFilePath + } + $ValidationErrors = $null + + # Additional parameter object provided yes/no + if ($additionalParameters) { + $DeploymentInputs += $additionalParameters + } + + $deploymentScope = Get-ScopeOfTemplateFile -TemplateFilePath $templateFilePath -Verbose + + # Generate a valid deployment name. Must match ^[-\w\._\(\)]+$ + do { + $deploymentName = ('{0}-{1}' -f $deploymentNamePrefix, (Get-Date -Format 'yyyyMMddTHHMMssffffZ'))[0..63] -join '' + } while ($deploymentName -notmatch '^[-\w\._\(\)]+$') + + if ($deploymentScope -ne 'resourceGroup') { + Write-Verbose "What-If Deployment Test with deployment name [$deploymentName]" -Verbose + $DeploymentInputs['DeploymentName'] = $deploymentName + } + + ################# + ## INVOKE TEST ## + ################# + switch ($deploymentScope) { + 'resourceGroup' { + if (-not [String]::IsNullOrEmpty($subscriptionId)) { + Write-Verbose ('Setting context to subscription [{0}]' -f $subscriptionId) + $null = Set-AzContext -Subscription $subscriptionId + } + if (-not (Get-AzResourceGroup -Name $resourceGroupName -ErrorAction 'SilentlyContinue')) { + if ($PSCmdlet.ShouldProcess("Resource group [$resourceGroupName] in location [$location]", 'Create')) { + $null = New-AzResourceGroup -Name $resourceGroupName -Location $location + } + } + if ($PSCmdlet.ShouldProcess('Resource group level deployment', 'WhatIf')) { + $res = New-AzResourceGroupDeployment @DeploymentInputs -WhatIf + } + break + } + 'subscription' { + if (-not [String]::IsNullOrEmpty($subscriptionId)) { + Write-Verbose ('Setting context to subscription [{0}]' -f $subscriptionId) + $null = Set-AzContext -Subscription $subscriptionId + } + if ($PSCmdlet.ShouldProcess('Subscription level deployment', 'WhatIf')) { + $res = New-AzDeployment @DeploymentInputs -Location $Location -WhatIf + } + break + } + 'managementGroup' { + if ($PSCmdlet.ShouldProcess('Management group level deployment', 'WhatIf')) { + $res = New-AzManagementGroupDeployment @DeploymentInputs -Location $Location -ManagementGroupId $ManagementGroupId -WhatIf + } + break + } + 'tenant' { + Write-Verbose 'Handling tenant level validation' + if ($PSCmdlet.ShouldProcess('Tenant level deployment', 'WhatIf')) { + $res = New-AzTenantDeployment @DeploymentInputs -Location $location -WhatIf + } + break + } + default { + throw "[$deploymentScope] is a non-supported template scope" + } + } + if ($ValidationErrors) { + if ($res.Details) { Write-Warning ($res.Details | ConvertTo-Json -Depth 10 | Out-String) } + if ($res.Message) { Write-Warning $res.Message } + Write-Error 'Template is not valid.' + } else { + Write-Verbose 'Template is valid' -Verbose + } + } + + end { + Write-Debug ('{0} exited' -f $MyInvocation.MyCommand) + } +} \ No newline at end of file From 554224777ca470ef6493c86a5fe76f4eaec4aeb2 Mon Sep 17 00:00:00 2001 From: Seif Bassem <38246040+sebassem@users.noreply.github.com> Date: Thu, 30 Nov 2023 12:43:13 +0200 Subject: [PATCH 18/22] fix: AVM deployment script workflow bug (#685) ## Description If you haven't already, read the full [contribution guide](https://github.com/Azure/bicep-registry-modules/blob/main/CONTRIBUTING.md). The guide may have changed since the last time you read it, so please double-check. Once you are done and ready to submit your PR, edit the PR description and run through the relevant checklist below. Enable GitHub Worksflows in your fork to enable auto-generation of assets with our [GitHub Action](/.github/workflows/push-auto-generate.yml). To trigger GitHub Actions after auto-generation, [add a GitHub PAT](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) as a secret in your forked repository called `PAT`. ## Adding a new module - [ ] A proposal has been submitted and approved. - [ ] I have included "Closes #{module_proposal_issue_number}" in the PR description. - [ ] I have run `brm validate` locally to verify the module files. - [ ] I have run deployment tests locally to ensure the module is deployable. ## Updating an existing module - [X] This is a bug fix: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [X] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] I have run `brm validate` locally to verify the module files. - [ ] I have run deployment tests locally to ensure the module is deployable. - [ ] I have read the [Updating an existing module](https://github.com/Azure/bicep-registry-modules/blob/main/CONTRIBUTING.md#updating-an-existing-module) section in the contributing guide and updated the `version.json` file properly: - [ ] The PR contains backwards compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`. - [ ] The PR contains backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] The PR contains breaking changes, and I have bumped the MAJOR version in `version.json`. - [ ] I have updated the examples in README with the latest module version number. --------- Co-authored-by: Alexander Sehr Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> Co-authored-by: ChrisSidebotham-MSFT <48600046+ChrisSidebotham@users.noreply.github.com> --- .github/workflows/avm.res.resources.deployment-script.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/avm.res.resources.deployment-script.yml b/.github/workflows/avm.res.resources.deployment-script.yml index 8a696d2ab0..c8f0d7b2ea 100644 --- a/.github/workflows/avm.res.resources.deployment-script.yml +++ b/.github/workflows/avm.res.resources.deployment-script.yml @@ -34,7 +34,7 @@ on: env: modulePath: "avm/res/resources/deployment-script" - workflowPath: ".github/workflows/avm.res.resources.deployment-script" + workflowPath: ".github/workflows/avm.res.resources.deployment-script.yml" concurrency: group: ${{ github.workflow }} From 09e5c03c91b1fa51835d4850b3d8ecab8187e08d Mon Sep 17 00:00:00 2001 From: Seif Bassem <38246040+sebassem@users.noreply.github.com> Date: Thu, 30 Nov 2023 13:36:29 +0200 Subject: [PATCH 19/22] fix: AVM deployment script - Docs change for publish (#686) ## Description If you haven't already, read the full [contribution guide](https://github.com/Azure/bicep-registry-modules/blob/main/CONTRIBUTING.md). The guide may have changed since the last time you read it, so please double-check. Once you are done and ready to submit your PR, edit the PR description and run through the relevant checklist below. Enable GitHub Worksflows in your fork to enable auto-generation of assets with our [GitHub Action](/.github/workflows/push-auto-generate.yml). To trigger GitHub Actions after auto-generation, [add a GitHub PAT](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) as a secret in your forked repository called `PAT`. ## Adding a new module - [ ] A proposal has been submitted and approved. - [ ] I have included "Closes #{module_proposal_issue_number}" in the PR description. - [ ] I have run `brm validate` locally to verify the module files. - [ ] I have run deployment tests locally to ensure the module is deployable. ## Updating an existing module - [X] This is a bug fix: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [X] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] I have run `brm validate` locally to verify the module files. - [ ] I have run deployment tests locally to ensure the module is deployable. - [ ] I have read the [Updating an existing module](https://github.com/Azure/bicep-registry-modules/blob/main/CONTRIBUTING.md#updating-an-existing-module) section in the contributing guide and updated the `version.json` file properly: - [ ] The PR contains backwards compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`. - [ ] The PR contains backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] The PR contains breaking changes, and I have bumped the MAJOR version in `version.json`. - [ ] I have updated the examples in README with the latest module version number. --------- Co-authored-by: Alexander Sehr Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> Co-authored-by: ChrisSidebotham-MSFT <48600046+ChrisSidebotham@users.noreply.github.com> --- avm/res/resources/deployment-script/README.md | 4 ++-- avm/res/resources/deployment-script/main.bicep | 2 +- avm/res/resources/deployment-script/main.json | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/avm/res/resources/deployment-script/README.md b/avm/res/resources/deployment-script/README.md index 57e1557f0e..510aaaa1cc 100644 --- a/avm/res/resources/deployment-script/README.md +++ b/avm/res/resources/deployment-script/README.md @@ -719,7 +719,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script: | [`location`](#parameter-location) | string | Location for all resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | | [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | -| [`primaryScriptUri`](#parameter-primaryscripturi) | string | Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent instead. | +| [`primaryScriptUri`](#parameter-primaryscripturi) | string | Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent parameter instead. | | [`retentionInterval`](#parameter-retentioninterval) | string | Interval for which the service retains the script resource after it reaches a terminal state. Resource will be deleted when this duration expires. Duration is based on ISO 8601 pattern (for example P7D means one week). | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`runOnce`](#parameter-runonce) | bool | When set to false, script will run every time the template is deployed. When set to true, the script will only run once. | @@ -869,7 +869,7 @@ Name of the Deployment Script. ### Parameter: `primaryScriptUri` -Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent instead. +Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent parameter instead. - Required: No - Type: string diff --git a/avm/res/resources/deployment-script/main.bicep b/avm/res/resources/deployment-script/main.bicep index 001a97cc94..970b48f7c6 100644 --- a/avm/res/resources/deployment-script/main.bicep +++ b/avm/res/resources/deployment-script/main.bicep @@ -34,7 +34,7 @@ param azCliVersion string? @description('Optional. Script body. Max length: 32000 characters. To run an external script, use primaryScriptURI instead.') param scriptContent string? -@description('Optional. Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent instead.') +@description('Optional. Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent parameter instead.') param primaryScriptUri string? @metadata({ diff --git a/avm/res/resources/deployment-script/main.json b/avm/res/resources/deployment-script/main.json index aad829ed7c..76dd745b41 100644 --- a/avm/res/resources/deployment-script/main.json +++ b/avm/res/resources/deployment-script/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "18060507539317064739" + "templateHash": "15035964448255167860" }, "name": "Deployment Scripts", "description": "This module deploys Deployment Scripts.", @@ -183,7 +183,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent instead." + "description": "Optional. Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent parameter instead." } }, "environmentVariables": { From 1ced523b7a770f6516f676cd9458b81dd5ba3c33 Mon Sep 17 00:00:00 2001 From: Erika Gressi <56914614+eriqua@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:51:54 +0000 Subject: [PATCH 20/22] feat: Filter PSRule validation on required test files (#684) ## Description - Filter PSRule validation only on defaults and waf-aligned test files - Added filter as action input regex default value - Updated job names for more readability ![image](https://github.com/Azure/bicep-registry-modules/assets/56914614/1107a27b-0d54-4bfa-9062-09ef37bf2b28) | Pipeline | | - | | [![avm.res.network.virtual-network](https://github.com/eriqua/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml/badge.svg)](https://github.com/eriqua/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml) | | [![avm.res.network.private-endpoint](https://github.com/eriqua/bicep-registry-modules/actions/workflows/avm.res.network.private-endpoint.yml/badge.svg)](https://github.com/eriqua/bicep-registry-modules/actions/workflows/avm.res.network.private-endpoint.yml) | | [![avm.res.event-grid.domain](https://github.com/eriqua/bicep-registry-modules/actions/workflows/avm.res.event-grid.domain.yml/badge.svg)](https://github.com/eriqua/bicep-registry-modules/actions/workflows/avm.res.event-grid.domain.yml) | --------- Co-authored-by: Alexander Sehr Co-authored-by: ChrisSidebotham-MSFT <48600046+ChrisSidebotham@users.noreply.github.com> --- .../avm-getModuleTestFiles/action.yml | 33 ++++++++++++++++--- .../workflows/avm.res.batch.batch-account.yml | 4 ++- .../avm.res.cognitive-services.account.yml | 4 ++- .../avm.res.compute.ssh-public-key.yml | 4 ++- ...res.db-for-postgre-sql.flexible-server.yml | 4 ++- .../workflows/avm.res.event-grid.domain.yml | 4 ++- .../avm.res.event-grid.system-topic.yml | 4 ++- .../workflows/avm.res.event-grid.topic.yml | 4 ++- .../avm.res.insights.action-group.yml | 4 ++- .../workflows/avm.res.insights.component.yml | 4 ++- .../avm.res.insights.diagnostic-setting.yml | 4 ++- .github/workflows/avm.res.key-vault.vault.yml | 4 ++- ...res.kubernetes-configuration.extension.yml | 4 ++- ...netes-configuration.flux-configuration.yml | 4 ++- .github/workflows/avm.res.logic.workflow.yml | 4 ++- ...avm.res.network.dns-forwarding-ruleset.yml | 4 ++- .../avm.res.network.dns-resolver.yml | 4 ++- .../workflows/avm.res.network.dns-zone.yml | 4 ++- .../avm.res.network.express-route-circuit.yml | 4 ++- .../avm.res.network.express-route-gateway.yml | 4 ++- .../avm.res.network.load-balancer.yml | 4 ++- .../avm.res.network.network-interface.yml | 4 ++- .../avm.res.network.private-dns-zone.yml | 4 ++- .../avm.res.network.private-endpoint.yml | 4 ++- .../avm.res.network.public-ip-address.yml | 4 ++- .../workflows/avm.res.network.route-table.yml | 4 ++- .../avm.res.network.virtual-network.yml | 4 ++- ...avm.res.operational-insights.workspace.yml | 4 ++- ...avm.res.operations-management.solution.yml | 4 ++- .../avm.res.power-bi-dedicated.capacity.yml | 4 ++- .../avm.res.resource-graph.query.yml | 4 ++- .../avm.res.resources.deployment-script.yml | 4 ++- .../avm.res.search.search-service.yml | 4 ++- .github/workflows/avm.res.sql.server.yml | 4 ++- .github/workflows/avm.template.module.yml | 12 ++++--- 35 files changed, 135 insertions(+), 42 deletions(-) diff --git a/.github/actions/templates/avm-getModuleTestFiles/action.yml b/.github/actions/templates/avm-getModuleTestFiles/action.yml index 2e0a37ebe2..16d85a86d8 100644 --- a/.github/actions/templates/avm-getModuleTestFiles/action.yml +++ b/.github/actions/templates/avm-getModuleTestFiles/action.yml @@ -5,32 +5,38 @@ inputs: modulePath: description: "The path to the module's folder" required: true + psRuleFilterRegex: + description: "The regex used to filter PSRule compliant files" + required: true + default: "(defaults|waf-aligned)" outputs: moduleTestFilePaths: description: "The module test files to use for template evaluation" value: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: + description: "The module test files to use for PSRule evaluation" + value: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} runs: using: "composite" steps: - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths shell: pwsh run: | # Grouping task logs - Write-Output '::group::Get parameter files' - # Load used functions + Write-Output '::group::Get all test files' # Get the list of parameter file paths $moduleFolderPath = Join-Path $env:GITHUB_WORKSPACE '${{ inputs.modulePath }}' - $testFilePaths = (Get-ChildItem -Path $moduleFolderPath -Recurse -Filter 'main.test.bicep').FullName | Sort-Object + $testFilePaths = (Get-ChildItem -Path $moduleFolderPath -Recurse -Filter 'main.test.bicep').FullName | Sort-Object $testFilePaths = $testFilePaths | ForEach-Object { $_.Replace($moduleFolderPath, '').Trim('\').Trim('/') } - Write-Verbose 'Found module test files' -Verbose + Write-Verbose 'Found all module test files' -Verbose $testFilePaths | ForEach-Object { Write-Verbose "- [$_]" -Verbose } # Output values to be accessed by next jobs @@ -40,4 +46,21 @@ runs: } Write-Verbose "Publishing output: $compressedOutput" -Verbose Write-Output ('{0}={1}' -f 'moduleTestFilePaths', $compressedOutput) >> $env:GITHUB_OUTPUT + + Write-Output '::endgroup::' + + Write-Output '::group::Get PSRule test files' + $psRuleTestFilePaths = $testFilePaths | Where-Object { $_ -match '${{ inputs.psRuleFilterRegex }}' } + + Write-Verbose 'Found PSRule module test files' -Verbose + $psRuleTestFilePaths | ForEach-Object { Write-Verbose "- [$_]" -Verbose } + + # Output values to be accessed by next jobs + $psRuleCompressedOutput = $psRuleTestFilePaths | ConvertTo-Json -Compress + if($psRuleCompressedOutput -notmatch "\[.*\]") { + $psRuleCompressedOutput = "[$psRuleCompressedOutput]" + } + Write-Verbose "Publishing output: $psRuleCompressedOutput" -Verbose + Write-Output ('{0}={1}' -f 'psRuleModuleTestFilePaths', $psRuleCompressedOutput) >> $env:GITHUB_OUTPUT + Write-Output '::endgroup::' diff --git a/.github/workflows/avm.res.batch.batch-account.yml b/.github/workflows/avm.res.batch.batch-account.yml index 5f07ffab60..3d6963efb3 100644 --- a/.github/workflows/avm.res.batch.batch-account.yml +++ b/.github/workflows/avm.res.batch.batch-account.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.cognitive-services.account.yml b/.github/workflows/avm.res.cognitive-services.account.yml index b8a3acb019..dc8ecd4f4b 100644 --- a/.github/workflows/avm.res.cognitive-services.account.yml +++ b/.github/workflows/avm.res.cognitive-services.account.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.compute.ssh-public-key.yml b/.github/workflows/avm.res.compute.ssh-public-key.yml index f0c1fdd5d5..05b11209b4 100644 --- a/.github/workflows/avm.res.compute.ssh-public-key.yml +++ b/.github/workflows/avm.res.compute.ssh-public-key.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.db-for-postgre-sql.flexible-server.yml b/.github/workflows/avm.res.db-for-postgre-sql.flexible-server.yml index a2fee2b4e0..549b861b35 100644 --- a/.github/workflows/avm.res.db-for-postgre-sql.flexible-server.yml +++ b/.github/workflows/avm.res.db-for-postgre-sql.flexible-server.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.event-grid.domain.yml b/.github/workflows/avm.res.event-grid.domain.yml index 5edb93b540..7e38c25ff0 100644 --- a/.github/workflows/avm.res.event-grid.domain.yml +++ b/.github/workflows/avm.res.event-grid.domain.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.event-grid.system-topic.yml b/.github/workflows/avm.res.event-grid.system-topic.yml index 35a2bf90d1..f90ffa705d 100644 --- a/.github/workflows/avm.res.event-grid.system-topic.yml +++ b/.github/workflows/avm.res.event-grid.system-topic.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.event-grid.topic.yml b/.github/workflows/avm.res.event-grid.topic.yml index 3eb80d2bac..fd0d834d71 100644 --- a/.github/workflows/avm.res.event-grid.topic.yml +++ b/.github/workflows/avm.res.event-grid.topic.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.insights.action-group.yml b/.github/workflows/avm.res.insights.action-group.yml index 71dbd20b0f..bb1eede980 100644 --- a/.github/workflows/avm.res.insights.action-group.yml +++ b/.github/workflows/avm.res.insights.action-group.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.insights.component.yml b/.github/workflows/avm.res.insights.component.yml index f08d42b78c..d7590c6835 100644 --- a/.github/workflows/avm.res.insights.component.yml +++ b/.github/workflows/avm.res.insights.component.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.insights.diagnostic-setting.yml b/.github/workflows/avm.res.insights.diagnostic-setting.yml index d9921b5c51..f44aeeef6e 100644 --- a/.github/workflows/avm.res.insights.diagnostic-setting.yml +++ b/.github/workflows/avm.res.insights.diagnostic-setting.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.key-vault.vault.yml b/.github/workflows/avm.res.key-vault.vault.yml index a1b6732fc9..7c06d7e0da 100644 --- a/.github/workflows/avm.res.key-vault.vault.yml +++ b/.github/workflows/avm.res.key-vault.vault.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.kubernetes-configuration.extension.yml b/.github/workflows/avm.res.kubernetes-configuration.extension.yml index 2b677abc15..73eab58640 100644 --- a/.github/workflows/avm.res.kubernetes-configuration.extension.yml +++ b/.github/workflows/avm.res.kubernetes-configuration.extension.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.kubernetes-configuration.flux-configuration.yml b/.github/workflows/avm.res.kubernetes-configuration.flux-configuration.yml index e2b030e430..e2444826b4 100644 --- a/.github/workflows/avm.res.kubernetes-configuration.flux-configuration.yml +++ b/.github/workflows/avm.res.kubernetes-configuration.flux-configuration.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.logic.workflow.yml b/.github/workflows/avm.res.logic.workflow.yml index a5c7bc2bc7..1d420c2152 100644 --- a/.github/workflows/avm.res.logic.workflow.yml +++ b/.github/workflows/avm.res.logic.workflow.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.network.dns-forwarding-ruleset.yml b/.github/workflows/avm.res.network.dns-forwarding-ruleset.yml index 0466115f8b..ddd52b635f 100644 --- a/.github/workflows/avm.res.network.dns-forwarding-ruleset.yml +++ b/.github/workflows/avm.res.network.dns-forwarding-ruleset.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.network.dns-resolver.yml b/.github/workflows/avm.res.network.dns-resolver.yml index e16affaed8..67bea4285b 100644 --- a/.github/workflows/avm.res.network.dns-resolver.yml +++ b/.github/workflows/avm.res.network.dns-resolver.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.network.dns-zone.yml b/.github/workflows/avm.res.network.dns-zone.yml index 7ea7e1a99f..88160e264f 100644 --- a/.github/workflows/avm.res.network.dns-zone.yml +++ b/.github/workflows/avm.res.network.dns-zone.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.network.express-route-circuit.yml b/.github/workflows/avm.res.network.express-route-circuit.yml index bc4e20a727..f41e82b3fc 100644 --- a/.github/workflows/avm.res.network.express-route-circuit.yml +++ b/.github/workflows/avm.res.network.express-route-circuit.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.network.express-route-gateway.yml b/.github/workflows/avm.res.network.express-route-gateway.yml index 7a0e195db6..e9963771c2 100644 --- a/.github/workflows/avm.res.network.express-route-gateway.yml +++ b/.github/workflows/avm.res.network.express-route-gateway.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.network.load-balancer.yml b/.github/workflows/avm.res.network.load-balancer.yml index d20b73c3e7..7fe8f4f5b9 100644 --- a/.github/workflows/avm.res.network.load-balancer.yml +++ b/.github/workflows/avm.res.network.load-balancer.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.network.network-interface.yml b/.github/workflows/avm.res.network.network-interface.yml index e8c80c2b15..768d83f9c7 100644 --- a/.github/workflows/avm.res.network.network-interface.yml +++ b/.github/workflows/avm.res.network.network-interface.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.network.private-dns-zone.yml b/.github/workflows/avm.res.network.private-dns-zone.yml index d2560f4586..547793820f 100644 --- a/.github/workflows/avm.res.network.private-dns-zone.yml +++ b/.github/workflows/avm.res.network.private-dns-zone.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.network.private-endpoint.yml b/.github/workflows/avm.res.network.private-endpoint.yml index c417943020..e8610f11b4 100644 --- a/.github/workflows/avm.res.network.private-endpoint.yml +++ b/.github/workflows/avm.res.network.private-endpoint.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.network.public-ip-address.yml b/.github/workflows/avm.res.network.public-ip-address.yml index 51e2dc0f6d..b262b54ee7 100644 --- a/.github/workflows/avm.res.network.public-ip-address.yml +++ b/.github/workflows/avm.res.network.public-ip-address.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.network.route-table.yml b/.github/workflows/avm.res.network.route-table.yml index d2614340da..ec546ead9a 100644 --- a/.github/workflows/avm.res.network.route-table.yml +++ b/.github/workflows/avm.res.network.route-table.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.network.virtual-network.yml b/.github/workflows/avm.res.network.virtual-network.yml index 6bddce3b9a..e9c8b82f20 100644 --- a/.github/workflows/avm.res.network.virtual-network.yml +++ b/.github/workflows/avm.res.network.virtual-network.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.operational-insights.workspace.yml b/.github/workflows/avm.res.operational-insights.workspace.yml index 4647b3de74..9f534ab614 100644 --- a/.github/workflows/avm.res.operational-insights.workspace.yml +++ b/.github/workflows/avm.res.operational-insights.workspace.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.operations-management.solution.yml b/.github/workflows/avm.res.operations-management.solution.yml index 6378665a69..a7702f866b 100644 --- a/.github/workflows/avm.res.operations-management.solution.yml +++ b/.github/workflows/avm.res.operations-management.solution.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.power-bi-dedicated.capacity.yml b/.github/workflows/avm.res.power-bi-dedicated.capacity.yml index 2966314f0b..7c3b0cae28 100644 --- a/.github/workflows/avm.res.power-bi-dedicated.capacity.yml +++ b/.github/workflows/avm.res.power-bi-dedicated.capacity.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.resource-graph.query.yml b/.github/workflows/avm.res.resource-graph.query.yml index 356e0e2769..0ca2453b78 100644 --- a/.github/workflows/avm.res.resource-graph.query.yml +++ b/.github/workflows/avm.res.resource-graph.query.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.resources.deployment-script.yml b/.github/workflows/avm.res.resources.deployment-script.yml index c8f0d7b2ea..0c7d73f865 100644 --- a/.github/workflows/avm.res.resources.deployment-script.yml +++ b/.github/workflows/avm.res.resources.deployment-script.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.search.search-service.yml b/.github/workflows/avm.res.search.search-service.yml index 0e03e78372..1504588d1f 100644 --- a/.github/workflows/avm.res.search.search-service.yml +++ b/.github/workflows/avm.res.search.search-service.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.res.sql.server.yml b/.github/workflows/avm.res.sql.server.yml index f2dad4ff0f..3060fa092d 100644 --- a/.github/workflows/avm.res.sql.server.yml +++ b/.github/workflows/avm.res.sql.server.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/templates/avm-getWorkflowInput with: workflowPath: "${{ env.workflowPath}}" - - name: "Get parameter file paths" + - name: "Get module test file paths" id: get-module-test-file-paths uses: ./.github/actions/templates/avm-getModuleTestFiles with: @@ -64,6 +64,7 @@ jobs: outputs: workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" ############################## @@ -77,5 +78,6 @@ jobs: with: workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" secrets: inherit diff --git a/.github/workflows/avm.template.module.yml b/.github/workflows/avm.template.module.yml index aa7095244a..24d865078e 100644 --- a/.github/workflows/avm.template.module.yml +++ b/.github/workflows/avm.template.module.yml @@ -11,6 +11,10 @@ on: type: string description: "List of relative path to the module test files in JSON format" required: true + psRuleModuleTestFilePaths: + type: string + description: "List of relative path to the PSRule module test files in JSON format" + required: true modulePath: type: string description: "Relative path to the module folder" @@ -50,13 +54,13 @@ jobs: # PSRule validation # ######################### job_psrule_test: # Note: Please don't change this job name. It is used by the setEnvironment action to define which PS modules to install on runners. - name: "PSRule validation" + name: "PSRule" runs-on: ubuntu-20.04 if: (fromJson(inputs.workflowInput)).staticValidation == 'true' strategy: fail-fast: false matrix: - moduleTestFilePaths: ${{ fromJson(inputs.moduleTestFilePaths) }} + psRuleModuleTestFilePaths: ${{ fromJson(inputs.psRuleModuleTestFilePaths) }} steps: - name: Checkout uses: actions/checkout@v4 @@ -65,7 +69,7 @@ jobs: - name: Set PSRule validation uses: ./.github/actions/templates/avm-validateModulePSRule with: - templateFilePath: "${{ inputs.modulePath }}/${{ matrix.moduleTestFilePaths }}" + templateFilePath: "${{ inputs.modulePath }}/${{ matrix.psRuleModuleTestFilePaths }}" subscriptionId: "${{ secrets.ARM_SUBSCRIPTION_ID }}" managementGroupId: "${{ secrets.ARM_MGMTGROUP_ID }}" psrulePath: "avm/utilities/pipelines/staticValidation/psrule" #'${{ github.workspace }}/avm' @@ -74,7 +78,7 @@ jobs: # Deployment validation # ############################# job_module_deploy_validation: # Note: Please don't change this job name. It is used by the setEnvironment action to define which PS modules to install on runners. - name: "Deployment validation" + name: "Deploy" runs-on: ubuntu-20.04 if: | !cancelled() && From 73d081cd4e0861219d070e37103a3cec834a5bd8 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Thu, 30 Nov 2023 18:57:55 +0100 Subject: [PATCH 21/22] feat: Updated PE version references (#621) ## Description - Updated PE version references - Added test cases - Updated casing | Pipeline | | - | | [![avm.res.cognitive-services.account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml/badge.svg?branch=users%2Falsehr%2FpeUpdate)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml) | | [![avm.res.batch.batch-account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.batch.batch-account.yml/badge.svg?branch=users%2Falsehr%2FpeUpdate)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.batch.batch-account.yml) | | [![avm.res.key-vault.vault](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2FpeUpdate)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) | | [![avm.res.network.private-endpoint](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.private-endpoint.yml/badge.svg?branch=users%2Falsehr%2FpeUpdate)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.private-endpoint.yml) | | [![avm.res.search.search-service](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.search.search-service.yml/badge.svg?branch=users%2Falsehr%2FpeUpdate)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.search.search-service.yml) | | [![avm.res.sql.server](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml/badge.svg?branch=users%2Falsehr%2FpeUpdate&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml) | --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/batch/batch-account/README.md | 88 +++++- avm/res/batch/batch-account/main.bicep | 34 ++- avm/res/batch/batch-account/main.json | 260 ++++++++++++++---- .../tests/e2e/max/main.test.bicep | 18 ++ avm/res/cognitive-services/account/README.md | 88 +++++- avm/res/cognitive-services/account/main.bicep | 34 ++- avm/res/cognitive-services/account/main.json | 260 ++++++++++++++---- .../account/tests/e2e/max/main.test.bicep | 18 ++ avm/res/key-vault/vault/README.md | 138 +++++++++- avm/res/key-vault/vault/main.bicep | 34 ++- avm/res/key-vault/vault/main.json | 260 ++++++++++++++---- .../vault/tests/e2e/max/main.test.bicep | 18 ++ .../e2e/private-endpoint/dependencies.bicep | 11 + .../e2e/private-endpoint/main.test.bicep | 26 ++ avm/res/network/private-endpoint/README.md | 12 +- avm/res/network/private-endpoint/main.bicep | 6 +- avm/res/network/private-endpoint/main.json | 6 +- avm/res/search/search-service/README.md | 2 +- avm/res/search/search-service/main.bicep | 15 +- avm/res/search/search-service/main.json | 143 +++++++--- avm/res/sql/server/README.md | 54 +++- avm/res/sql/server/main.bicep | 24 +- avm/res/sql/server/main.json | 151 +++++++--- .../sql/server/tests/e2e/pe/main.test.bicep | 18 ++ 24 files changed, 1409 insertions(+), 309 deletions(-) diff --git a/avm/res/batch/batch-account/README.md b/avm/res/batch/batch-account/README.md index 5c5f32c55f..b59fde3e2d 100644 --- a/avm/res/batch/batch-account/README.md +++ b/avm/res/batch/batch-account/README.md @@ -226,6 +226,24 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { poolAllocationMode: 'BatchService' privateEndpoints: [ { + customDnsConfigs: [ + { + fqdn: 'abc.batch.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'batchAccount' + memberName: 'batchAccount' + privateIPAddress: '10.0.0.10' + } + } + ] privateDnsZoneResourceIds: [ '' ] @@ -343,6 +361,24 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { "privateEndpoints": { "value": [ { + "customDnsConfigs": [ + { + "fqdn": "abc.batch.com", + "ipAddresses": [ + "10.0.0.10" + ] + } + ], + "ipConfigurations": [ + { + "name": "myIPconfig", + "properties": { + "groupId": "batchAccount", + "memberName": "batchAccount", + "privateIPAddress": "10.0.0.10" + } + } + ], "privateDnsZoneResourceIds": [ "" ], @@ -895,14 +931,20 @@ Optional. Custom DNS configurations. | Name | Required | Type | Description | | :-- | :-- | :--| :-- | -| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | No | string | | -| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | Yes | array | | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | No | string | Required. Fqdn that resolves to private endpoint IP address. | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | Yes | array | Required. A list of private IP addresses of the private endpoint. | ### Parameter: `privateEndpoints.customDnsConfigs.fqdn` + +Required. Fqdn that resolves to private endpoint IP address. + - Required: No - Type: string ### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` + +Required. A list of private IP addresses of the private endpoint. + - Required: Yes - Type: array @@ -930,28 +972,52 @@ Optional. A list of IP configurations of the private endpoint. This will be used | Name | Required | Type | Description | | :-- | :-- | :--| :-- | -| [`groupId`](#parameter-privateendpointsipconfigurationsgroupid) | Yes | string | | -| [`memberName`](#parameter-privateendpointsipconfigurationsmembername) | Yes | string | | -| [`name`](#parameter-privateendpointsipconfigurationsname) | Yes | string | | -| [`privateIpAddress`](#parameter-privateendpointsipconfigurationsprivateipaddress) | Yes | string | | +| [`name`](#parameter-privateendpointsipconfigurationsname) | Yes | string | Required. The name of the resource that is unique within a resource group. | +| [`properties`](#parameter-privateendpointsipconfigurationsproperties) | Yes | object | Required. Properties of private endpoint IP configurations. | + +### Parameter: `privateEndpoints.ipConfigurations.name` + +Required. The name of the resource that is unique within a resource group. -### Parameter: `privateEndpoints.ipConfigurations.groupId` - Required: Yes - Type: string -### Parameter: `privateEndpoints.ipConfigurations.memberName` +### Parameter: `privateEndpoints.ipConfigurations.properties` + +Required. Properties of private endpoint IP configurations. + +- Required: Yes +- Type: object + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | Yes | string | Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. | +| [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | Yes | string | Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | Yes | string | Required. A private IP address obtained from the private endpoint's subnet. | + +### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` + +Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. + - Required: Yes - Type: string -### Parameter: `privateEndpoints.ipConfigurations.name` +### Parameter: `privateEndpoints.ipConfigurations.properties.memberName` + +Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. + - Required: Yes - Type: string -### Parameter: `privateEndpoints.ipConfigurations.privateIpAddress` +### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` + +Required. A private IP address obtained from the private endpoint's subnet. + - Required: Yes - Type: string + ### Parameter: `privateEndpoints.location` Optional. The location to deploy the private endpoint to. @@ -1154,4 +1220,4 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/private-endpoint:0.2.0` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.3.1` | Remote reference | diff --git a/avm/res/batch/batch-account/main.bicep b/avm/res/batch/batch-account/main.bicep index 147b04221a..10378fe471 100644 --- a/avm/res/batch/batch-account/main.bicep +++ b/avm/res/batch/batch-account/main.bicep @@ -204,14 +204,21 @@ resource batchAccount_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@ scope: batchAccount }] -module batchAccount_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.2.0' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { +module batchAccount_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-BatchAccount-PrivateEndpoint-${index}' params: { - groupIds: [ - privateEndpoint.?service ?? 'batchAccount' + privateLinkServiceConnections: [ + { + name: name + properties: { + privateLinkServiceId: batchAccount.id + groupIds: [ + privateEndpoint.?service ?? 'batchAccount' + ] + } + } ] name: privateEndpoint.?name ?? 'pep-${last(split(batchAccount.id, '/'))}-${privateEndpoint.?service ?? 'batchAccount'}-${index}' - serviceResourceId: batchAccount.id subnetResourceId: privateEndpoint.subnetResourceId enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location @@ -343,16 +350,29 @@ type privateEndpointType = { @description('Optional. Custom DNS configurations.') customDnsConfigs: { + @description('Required. Fqdn that resolves to private endpoint IP address.') fqdn: string? + + @description('Required. A list of private IP addresses of the private endpoint.') ipAddresses: string[] }[]? @description('Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints.') ipConfigurations: { + @description('Required. The name of the resource that is unique within a resource group.') name: string - groupId: string - memberName: string - privateIpAddress: string + + @description('Required. Properties of private endpoint IP configurations.') + properties: { + @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to.') + groupId: string + + @description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to.') + memberName: string + + @description('Required. A private IP address obtained from the private endpoint\'s subnet.') + privateIPAddress: string + } }[]? @description('Optional. Application security groups in which the private endpoint IP configuration is included.') diff --git a/avm/res/batch/batch-account/main.json b/avm/res/batch/batch-account/main.json index 8ba5f23677..1e54643441 100644 --- a/avm/res/batch/batch-account/main.json +++ b/avm/res/batch/batch-account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "16960327826957585535" + "templateHash": "2440542999931048241" }, "name": "Batch Accounts", "description": "This module deploys a Batch Account.", @@ -241,12 +241,18 @@ "properties": { "fqdn": { "type": "string", - "nullable": true + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } }, "ipAddresses": { "type": "array", "items": { "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." } } } @@ -262,16 +268,36 @@ "type": "object", "properties": { "name": { - "type": "string" - }, - "groupId": { - "type": "string" - }, - "memberName": { - "type": "string" + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } }, - "privateIpAddress": { - "type": "string" + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } } } }, @@ -768,17 +794,22 @@ }, "mode": "Incremental", "parameters": { - "groupIds": { + "privateLinkServiceConnections": { "value": [ - "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'batchAccount')]" + { + "name": "[parameters('name')]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.Batch/batchAccounts', parameters('name'))]", + "groupIds": [ + "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'batchAccount')]" + ] + } + } ] }, "name": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Batch/batchAccounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'batchAccount'), copyIndex()))]" }, - "serviceResourceId": { - "value": "[resourceId('Microsoft.Batch/batchAccounts', parameters('name'))]" - }, "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, @@ -827,7 +858,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "2788827530274342759" + "templateHash": "2821141217598568122" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -842,7 +873,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -924,6 +955,154 @@ } }, "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private ip address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint ip address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private ip addresses of the private endpoint." + } + } + } + }, + "nullable": true } }, "parameters": { @@ -939,12 +1118,6 @@ "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "serviceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource that needs to be connected to the network." - } - }, "applicationSecurityGroupResourceIds": { "type": "array", "nullable": true, @@ -960,18 +1133,11 @@ } }, "ipConfigurations": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/ipConfigurationsType", "metadata": { "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." } }, - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." - } - }, "privateDnsZoneGroupName": { "type": "string", "nullable": true, @@ -1002,7 +1168,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -1013,17 +1179,21 @@ } }, "customDnsConfigs": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/customDnsConfigType", "metadata": { "description": "Optional. Custom DNS configurations." } }, "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." } }, "enableTelemetry": { @@ -1053,7 +1223,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.2.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1089,15 +1259,7 @@ "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": [ - { - "name": "[parameters('name')]", - "properties": { - "privateLinkServiceId": "[parameters('serviceResourceId')]", - "groupIds": "[parameters('groupIds')]" - } - } - ], + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", "subnet": { "id": "[parameters('subnetResourceId')]" } @@ -1127,7 +1289,7 @@ "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/batch/batch-account/tests/e2e/max/main.test.bicep b/avm/res/batch/batch-account/tests/e2e/max/main.test.bicep index 4ec2feaf2e..a9ff31f549 100644 --- a/avm/res/batch/batch-account/tests/e2e/max/main.test.bicep +++ b/avm/res/batch/batch-account/tests/e2e/max/main.test.bicep @@ -105,6 +105,24 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' principalType: 'ServicePrincipal' } ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'batchAccount' + memberName: 'batchAccount' + privateIPAddress: '10.0.0.10' + } + } + ] + customDnsConfigs: [ + { + fqdn: 'abc.batch.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] } ] networkProfile: { diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index b63f01ca87..665b62d9e9 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -161,6 +161,24 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } privateEndpoints: [ { + customDnsConfigs: [ + { + fqdn: 'abc.account.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'account' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } + ] privateDnsZoneResourceIds: [ '' ] @@ -289,6 +307,24 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "privateEndpoints": { "value": [ { + "customDnsConfigs": [ + { + "fqdn": "abc.account.com", + "ipAddresses": [ + "10.0.0.10" + ] + } + ], + "ipConfigurations": [ + { + "name": "myIPconfig", + "properties": { + "groupId": "account", + "memberName": "default", + "privateIPAddress": "10.0.0.10" + } + } + ], "privateDnsZoneResourceIds": [ "" ], @@ -1149,14 +1185,20 @@ Optional. Custom DNS configurations. | Name | Required | Type | Description | | :-- | :-- | :--| :-- | -| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | No | string | | -| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | Yes | array | | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | No | string | Required. Fqdn that resolves to private endpoint IP address. | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | Yes | array | Required. A list of private IP addresses of the private endpoint. | ### Parameter: `privateEndpoints.customDnsConfigs.fqdn` + +Required. Fqdn that resolves to private endpoint IP address. + - Required: No - Type: string ### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` + +Required. A list of private IP addresses of the private endpoint. + - Required: Yes - Type: array @@ -1184,28 +1226,52 @@ Optional. A list of IP configurations of the private endpoint. This will be used | Name | Required | Type | Description | | :-- | :-- | :--| :-- | -| [`groupId`](#parameter-privateendpointsipconfigurationsgroupid) | Yes | string | | -| [`memberName`](#parameter-privateendpointsipconfigurationsmembername) | Yes | string | | -| [`name`](#parameter-privateendpointsipconfigurationsname) | Yes | string | | -| [`privateIpAddress`](#parameter-privateendpointsipconfigurationsprivateipaddress) | Yes | string | | +| [`name`](#parameter-privateendpointsipconfigurationsname) | Yes | string | Required. The name of the resource that is unique within a resource group. | +| [`properties`](#parameter-privateendpointsipconfigurationsproperties) | Yes | object | Required. Properties of private endpoint IP configurations. | + +### Parameter: `privateEndpoints.ipConfigurations.name` + +Required. The name of the resource that is unique within a resource group. -### Parameter: `privateEndpoints.ipConfigurations.groupId` - Required: Yes - Type: string -### Parameter: `privateEndpoints.ipConfigurations.memberName` +### Parameter: `privateEndpoints.ipConfigurations.properties` + +Required. Properties of private endpoint IP configurations. + +- Required: Yes +- Type: object + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | Yes | string | Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. | +| [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | Yes | string | Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | Yes | string | Required. A private IP address obtained from the private endpoint's subnet. | + +### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` + +Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. + - Required: Yes - Type: string -### Parameter: `privateEndpoints.ipConfigurations.name` +### Parameter: `privateEndpoints.ipConfigurations.properties.memberName` + +Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. + - Required: Yes - Type: string -### Parameter: `privateEndpoints.ipConfigurations.privateIpAddress` +### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` + +Required. A private IP address obtained from the private endpoint's subnet. + - Required: Yes - Type: string + ### Parameter: `privateEndpoints.location` Optional. The location to deploy the private endpoint to. @@ -1432,4 +1498,4 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/private-endpoint:0.2.0` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.3.1` | Remote reference | diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index 62ac4428ef..4e416c77dc 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -261,14 +261,21 @@ resource cognitiveService_diagnosticSettings 'Microsoft.Insights/diagnosticSetti scope: cognitiveService }] -module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.2.0' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { +module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-CognitiveService-PrivateEndpoint-${index}' params: { - groupIds: [ - privateEndpoint.?service ?? 'account' + privateLinkServiceConnections: [ + { + name: name + properties: { + privateLinkServiceId: cognitiveService.id + groupIds: [ + privateEndpoint.?service ?? 'account' + ] + } + } ] name: privateEndpoint.?name ?? 'pep-${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' - serviceResourceId: cognitiveService.id subnetResourceId: privateEndpoint.subnetResourceId enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location @@ -403,16 +410,29 @@ type privateEndpointType = { @description('Optional. Custom DNS configurations.') customDnsConfigs: { + @description('Required. Fqdn that resolves to private endpoint IP address.') fqdn: string? + + @description('Required. A list of private IP addresses of the private endpoint.') ipAddresses: string[] }[]? @description('Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints.') ipConfigurations: { + @description('Required. The name of the resource that is unique within a resource group.') name: string - groupId: string - memberName: string - privateIpAddress: string + + @description('Required. Properties of private endpoint IP configurations.') + properties: { + @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to.') + groupId: string + + @description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to.') + memberName: string + + @description('Required. A private IP address obtained from the private endpoint\'s subnet.') + privateIPAddress: string + } }[]? @description('Optional. Application security groups in which the private endpoint IP configuration is included.') diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index 5966902ed5..37b334dccb 100644 --- a/avm/res/cognitive-services/account/main.json +++ b/avm/res/cognitive-services/account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "7267850394264518578" + "templateHash": "8113334263625418936" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -241,12 +241,18 @@ "properties": { "fqdn": { "type": "string", - "nullable": true + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } }, "ipAddresses": { "type": "array", "items": { "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." } } } @@ -262,16 +268,36 @@ "type": "object", "properties": { "name": { - "type": "string" - }, - "groupId": { - "type": "string" - }, - "memberName": { - "type": "string" + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } }, - "privateIpAddress": { - "type": "string" + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } } } }, @@ -808,17 +834,22 @@ }, "mode": "Incremental", "parameters": { - "groupIds": { + "privateLinkServiceConnections": { "value": [ - "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')]" + { + "name": "[parameters('name')]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "groupIds": [ + "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')]" + ] + } + } ] }, "name": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" }, - "serviceResourceId": { - "value": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" - }, "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, @@ -867,7 +898,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "2788827530274342759" + "templateHash": "2821141217598568122" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -882,7 +913,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -964,6 +995,154 @@ } }, "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private ip address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint ip address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private ip addresses of the private endpoint." + } + } + } + }, + "nullable": true } }, "parameters": { @@ -979,12 +1158,6 @@ "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "serviceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource that needs to be connected to the network." - } - }, "applicationSecurityGroupResourceIds": { "type": "array", "nullable": true, @@ -1000,18 +1173,11 @@ } }, "ipConfigurations": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/ipConfigurationsType", "metadata": { "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." } }, - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." - } - }, "privateDnsZoneGroupName": { "type": "string", "nullable": true, @@ -1042,7 +1208,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -1053,17 +1219,21 @@ } }, "customDnsConfigs": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/customDnsConfigType", "metadata": { "description": "Optional. Custom DNS configurations." } }, "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." } }, "enableTelemetry": { @@ -1093,7 +1263,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.2.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1129,15 +1299,7 @@ "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": [ - { - "name": "[parameters('name')]", - "properties": { - "privateLinkServiceId": "[parameters('serviceResourceId')]", - "groupIds": "[parameters('groupIds')]" - } - } - ], + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", "subnet": { "id": "[parameters('subnetResourceId')]" } @@ -1167,7 +1329,7 @@ "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/cognitive-services/account/tests/e2e/max/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/max/main.test.bicep index 5ee0cd261b..ac011a2766 100644 --- a/avm/res/cognitive-services/account/tests/e2e/max/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/max/main.test.bicep @@ -149,6 +149,24 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Environment: 'Non-Prod' Role: 'DeploymentValidation' } + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'account' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } + ] + customDnsConfigs: [ + { + fqdn: 'abc.account.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] } ] tags: { diff --git a/avm/res/key-vault/vault/README.md b/avm/res/key-vault/vault/README.md index 8a77180d71..15daab9c4a 100644 --- a/avm/res/key-vault/vault/README.md +++ b/avm/res/key-vault/vault/README.md @@ -235,6 +235,24 @@ module vault 'br/public:avm/res/key-vault/vault:' = { } privateEndpoints: [ { + customDnsConfigs: [ + { + fqdn: 'abc.keyvault.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'vault' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } + ] privateDnsZoneResourceIds: [ '' ] @@ -474,6 +492,24 @@ module vault 'br/public:avm/res/key-vault/vault:' = { "privateEndpoints": { "value": [ { + "customDnsConfigs": [ + { + "fqdn": "abc.keyvault.com", + "ipAddresses": [ + "10.0.0.10" + ] + } + ], + "ipConfigurations": [ + { + "name": "myIPconfig", + "properties": { + "groupId": "vault", + "memberName": "default", + "privateIPAddress": "10.0.0.10" + } + } + ], "privateDnsZoneResourceIds": [ "" ], @@ -585,9 +621,34 @@ module vault 'br/public:avm/res/key-vault/vault:' = { location: '' privateEndpoints: [ { + customDnsConfigs: [ + { + fqdn: 'abc.keyvault.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'vault' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } + ] privateDnsZoneResourceIds: [ '' ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -631,9 +692,34 @@ module vault 'br/public:avm/res/key-vault/vault:' = { "privateEndpoints": { "value": [ { + "customDnsConfigs": [ + { + "fqdn": "abc.keyvault.com", + "ipAddresses": [ + "10.0.0.10" + ] + } + ], + "ipConfigurations": [ + { + "name": "myIPconfig", + "properties": { + "groupId": "vault", + "memberName": "default", + "privateIPAddress": "10.0.0.10" + } + } + ], "privateDnsZoneResourceIds": [ "" ], + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], "subnetResourceId": "", "tags": { "Environment": "Non-Prod", @@ -1251,14 +1337,20 @@ Optional. Custom DNS configurations. | Name | Required | Type | Description | | :-- | :-- | :--| :-- | -| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | No | string | | -| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | Yes | array | | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | No | string | Required. Fqdn that resolves to private endpoint IP address. | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | Yes | array | Required. A list of private IP addresses of the private endpoint. | ### Parameter: `privateEndpoints.customDnsConfigs.fqdn` + +Required. Fqdn that resolves to private endpoint IP address. + - Required: No - Type: string ### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` + +Required. A list of private IP addresses of the private endpoint. + - Required: Yes - Type: array @@ -1286,28 +1378,52 @@ Optional. A list of IP configurations of the private endpoint. This will be used | Name | Required | Type | Description | | :-- | :-- | :--| :-- | -| [`groupId`](#parameter-privateendpointsipconfigurationsgroupid) | Yes | string | | -| [`memberName`](#parameter-privateendpointsipconfigurationsmembername) | Yes | string | | -| [`name`](#parameter-privateendpointsipconfigurationsname) | Yes | string | | -| [`privateIpAddress`](#parameter-privateendpointsipconfigurationsprivateipaddress) | Yes | string | | +| [`name`](#parameter-privateendpointsipconfigurationsname) | Yes | string | Required. The name of the resource that is unique within a resource group. | +| [`properties`](#parameter-privateendpointsipconfigurationsproperties) | Yes | object | Required. Properties of private endpoint IP configurations. | + +### Parameter: `privateEndpoints.ipConfigurations.name` + +Required. The name of the resource that is unique within a resource group. -### Parameter: `privateEndpoints.ipConfigurations.groupId` - Required: Yes - Type: string -### Parameter: `privateEndpoints.ipConfigurations.memberName` +### Parameter: `privateEndpoints.ipConfigurations.properties` + +Required. Properties of private endpoint IP configurations. + +- Required: Yes +- Type: object + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | Yes | string | Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. | +| [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | Yes | string | Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | Yes | string | Required. A private IP address obtained from the private endpoint's subnet. | + +### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` + +Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. + - Required: Yes - Type: string -### Parameter: `privateEndpoints.ipConfigurations.name` +### Parameter: `privateEndpoints.ipConfigurations.properties.memberName` + +Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. + - Required: Yes - Type: string -### Parameter: `privateEndpoints.ipConfigurations.privateIpAddress` +### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` + +Required. A private IP address obtained from the private endpoint's subnet. + - Required: Yes - Type: string + ### Parameter: `privateEndpoints.location` Optional. The location to deploy the private endpoint to. @@ -1511,4 +1627,4 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/private-endpoint:0.2.0` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.3.1` | Remote reference | diff --git a/avm/res/key-vault/vault/main.bicep b/avm/res/key-vault/vault/main.bicep index c07ffa48ba..28b0553884 100644 --- a/avm/res/key-vault/vault/main.bicep +++ b/avm/res/key-vault/vault/main.bicep @@ -239,14 +239,21 @@ module keyVault_keys 'key/main.bicep' = [for (key, index) in (keys ?? []): { } }] -module keyVault_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.2.0' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { +module keyVault_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-KeyVault-PrivateEndpoint-${index}' params: { - groupIds: [ - privateEndpoint.?service ?? 'vault' + privateLinkServiceConnections: [ + { + name: name + properties: { + privateLinkServiceId: keyVault.id + groupIds: [ + privateEndpoint.?service ?? 'vault' + ] + } + } ] name: privateEndpoint.?name ?? 'pep-${last(split(keyVault.id, '/'))}-${privateEndpoint.?service ?? 'vault'}-${index}' - serviceResourceId: keyVault.id subnetResourceId: privateEndpoint.subnetResourceId enableTelemetry: enableTelemetry location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location @@ -382,16 +389,29 @@ type privateEndpointType = { @description('Optional. Custom DNS configurations.') customDnsConfigs: { + @description('Required. Fqdn that resolves to private endpoint IP address.') fqdn: string? + + @description('Required. A list of private IP addresses of the private endpoint.') ipAddresses: string[] }[]? @description('Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints.') ipConfigurations: { + @description('Required. The name of the resource that is unique within a resource group.') name: string - groupId: string - memberName: string - privateIpAddress: string + + @description('Required. Properties of private endpoint IP configurations.') + properties: { + @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to.') + groupId: string + + @description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to.') + memberName: string + + @description('Required. A private IP address obtained from the private endpoint\'s subnet.') + privateIPAddress: string + } }[]? @description('Optional. Application security groups in which the private endpoint IP configuration is included.') diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index b9a9f93646..c3bc831762 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "665865372091259296" + "templateHash": "1282169260807050154" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -241,12 +241,18 @@ "properties": { "fqdn": { "type": "string", - "nullable": true + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } }, "ipAddresses": { "type": "array", "items": { "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." } } } @@ -262,16 +268,36 @@ "type": "object", "properties": { "name": { - "type": "string" - }, - "groupId": { - "type": "string" - }, - "memberName": { - "type": "string" + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } }, - "privateIpAddress": { - "type": "string" + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } } } }, @@ -1659,17 +1685,22 @@ }, "mode": "Incremental", "parameters": { - "groupIds": { + "privateLinkServiceConnections": { "value": [ - "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')]" + { + "name": "[parameters('name')]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.KeyVault/vaults', parameters('name'))]", + "groupIds": [ + "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')]" + ] + } + } ] }, "name": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex()))]" }, - "serviceResourceId": { - "value": "[resourceId('Microsoft.KeyVault/vaults', parameters('name'))]" - }, "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, @@ -1718,7 +1749,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "2788827530274342759" + "templateHash": "2821141217598568122" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -1733,7 +1764,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -1815,6 +1846,154 @@ } }, "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private ip address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint ip address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private ip addresses of the private endpoint." + } + } + } + }, + "nullable": true } }, "parameters": { @@ -1830,12 +2009,6 @@ "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "serviceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource that needs to be connected to the network." - } - }, "applicationSecurityGroupResourceIds": { "type": "array", "nullable": true, @@ -1851,18 +2024,11 @@ } }, "ipConfigurations": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/ipConfigurationsType", "metadata": { "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." } }, - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." - } - }, "privateDnsZoneGroupName": { "type": "string", "nullable": true, @@ -1893,7 +2059,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -1904,17 +2070,21 @@ } }, "customDnsConfigs": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/customDnsConfigType", "metadata": { "description": "Optional. Custom DNS configurations." } }, "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." } }, "enableTelemetry": { @@ -1944,7 +2114,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.2.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1980,15 +2150,7 @@ "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": [ - { - "name": "[parameters('name')]", - "properties": { - "privateLinkServiceId": "[parameters('serviceResourceId')]", - "groupIds": "[parameters('groupIds')]" - } - } - ], + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", "subnet": { "id": "[parameters('subnetResourceId')]" } @@ -2018,7 +2180,7 @@ "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/key-vault/vault/tests/e2e/max/main.test.bicep b/avm/res/key-vault/vault/tests/e2e/max/main.test.bicep index 5827070e98..6710a71e32 100644 --- a/avm/res/key-vault/vault/tests/e2e/max/main.test.bicep +++ b/avm/res/key-vault/vault/tests/e2e/max/main.test.bicep @@ -216,6 +216,24 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' principalType: 'ServicePrincipal' } ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'vault' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } + ] + customDnsConfigs: [ + { + fqdn: 'abc.keyvault.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] } ] roleAssignments: [ diff --git a/avm/res/key-vault/vault/tests/e2e/private-endpoint/dependencies.bicep b/avm/res/key-vault/vault/tests/e2e/private-endpoint/dependencies.bicep index b9eb57d972..a9999dcb53 100644 --- a/avm/res/key-vault/vault/tests/e2e/private-endpoint/dependencies.bicep +++ b/avm/res/key-vault/vault/tests/e2e/private-endpoint/dependencies.bicep @@ -4,6 +4,9 @@ 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' resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { @@ -47,8 +50,16 @@ resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { } } +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + @description('The resource ID of the created Virtual Network Subnet.') output subnetResourceId string = virtualNetwork.properties.subnets[0].id @description('The resource ID of the created Private DNS Zone.') output privateDNSResourceId string = privateDNSZone.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/key-vault/vault/tests/e2e/private-endpoint/main.test.bicep b/avm/res/key-vault/vault/tests/e2e/private-endpoint/main.test.bicep index ad4258b82f..c391bdf550 100644 --- a/avm/res/key-vault/vault/tests/e2e/private-endpoint/main.test.bicep +++ b/avm/res/key-vault/vault/tests/e2e/private-endpoint/main.test.bicep @@ -36,6 +36,7 @@ module nestedDependencies 'dependencies.bicep' = { name: '${uniqueString(deployment().name, location)}-nestedDependencies' params: { virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' location: location } } @@ -62,6 +63,31 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Environment: 'Non-Prod' Role: 'DeploymentValidation' } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'vault' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } + ] + customDnsConfigs: [ + { + fqdn: 'abc.keyvault.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] } ] tags: { diff --git a/avm/res/network/private-endpoint/README.md b/avm/res/network/private-endpoint/README.md index 0015b935b3..6fb235bb50 100644 --- a/avm/res/network/private-endpoint/README.md +++ b/avm/res/network/private-endpoint/README.md @@ -548,19 +548,19 @@ Custom DNS configurations. | Name | Required | Type | Description | | :-- | :-- | :--| :-- | -| [`fqdn`](#parameter-customdnsconfigsfqdn) | Yes | string | Required. Fqdn that resolves to private endpoint ip address. | -| [`ipAddresses`](#parameter-customdnsconfigsipaddresses) | Yes | array | Required. A list of private ip addresses of the private endpoint. | +| [`fqdn`](#parameter-customdnsconfigsfqdn) | Yes | string | Required. Fqdn that resolves to private endpoint IP address. | +| [`ipAddresses`](#parameter-customdnsconfigsipaddresses) | Yes | array | Required. A list of private IP addresses of the private endpoint. | ### Parameter: `customDnsConfigs.fqdn` -Required. Fqdn that resolves to private endpoint ip address. +Required. Fqdn that resolves to private endpoint IP address. - Required: Yes - Type: string ### Parameter: `customDnsConfigs.ipAddresses` -Required. A list of private ip addresses of the private endpoint. +Required. A list of private IP addresses of the private endpoint. - Required: Yes - Type: array @@ -608,7 +608,7 @@ Required. Properties of private endpoint IP configurations. | :-- | :-- | :--| :-- | | [`groupId`](#parameter-ipconfigurationspropertiesgroupid) | Yes | string | Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. | | [`memberName`](#parameter-ipconfigurationspropertiesmembername) | Yes | string | Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. | -| [`privateIPAddress`](#parameter-ipconfigurationspropertiesprivateipaddress) | Yes | string | Required. A private ip address obtained from the private endpoint's subnet. | +| [`privateIPAddress`](#parameter-ipconfigurationspropertiesprivateipaddress) | Yes | string | Required. A private IP address obtained from the private endpoint's subnet. | ### Parameter: `ipConfigurations.properties.groupId` @@ -626,7 +626,7 @@ Required. The member name of a group obtained from the remote resource that this ### Parameter: `ipConfigurations.properties.privateIPAddress` -Required. A private ip address obtained from the private endpoint's subnet. +Required. A private IP address obtained from the private endpoint's subnet. - Required: Yes - Type: string diff --git a/avm/res/network/private-endpoint/main.bicep b/avm/res/network/private-endpoint/main.bicep index 08399b166f..8ff37d7dbc 100644 --- a/avm/res/network/private-endpoint/main.bicep +++ b/avm/res/network/private-endpoint/main.bicep @@ -188,7 +188,7 @@ type ipConfigurationsType = { @description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to.') memberName: string - @description('Required. A private ip address obtained from the private endpoint\'s subnet.') + @description('Required. A private IP address obtained from the private endpoint\'s subnet.') privateIPAddress: string } }[]? @@ -228,9 +228,9 @@ type privateLinkServiceConnectionsType = { }[]? type customDnsConfigType = { - @description('Required. Fqdn that resolves to private endpoint ip address.') + @description('Required. Fqdn that resolves to private endpoint IP address.') fqdn: string - @description('Required. A list of private ip addresses of the private endpoint.') + @description('Required. A list of private IP addresses of the private endpoint.') ipAddresses: string[] }[]? diff --git a/avm/res/network/private-endpoint/main.json b/avm/res/network/private-endpoint/main.json index 7caa529b5d..0227bf8f8e 100644 --- a/avm/res/network/private-endpoint/main.json +++ b/avm/res/network/private-endpoint/main.json @@ -133,7 +133,7 @@ "privateIPAddress": { "type": "string", "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." + "description": "Required. A private IP address obtained from the private endpoint's subnet." } } }, @@ -236,7 +236,7 @@ "fqdn": { "type": "string", "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." + "description": "Required. Fqdn that resolves to private endpoint IP address." } }, "ipAddresses": { @@ -245,7 +245,7 @@ "type": "string" }, "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." + "description": "Required. A list of private IP addresses of the private endpoint." } } } diff --git a/avm/res/search/search-service/README.md b/avm/res/search/search-service/README.md index f5382fe232..096f5cd277 100644 --- a/avm/res/search/search-service/README.md +++ b/avm/res/search/search-service/README.md @@ -1180,4 +1180,4 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/private-endpoint:0.2.1` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.3.1` | Remote reference | diff --git a/avm/res/search/search-service/main.bicep b/avm/res/search/search-service/main.bicep index 42a3bb2afc..54b20f22a4 100644 --- a/avm/res/search/search-service/main.bicep +++ b/avm/res/search/search-service/main.bicep @@ -201,14 +201,21 @@ resource searchService_roleAssignments 'Microsoft.Authorization/roleAssignments@ scope: searchService }] -module searchService_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.2.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { +module searchService_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-searchService-PrivateEndpoint-${index}' params: { - groupIds: [ - privateEndpoint.?service ?? 'searchService' + privateLinkServiceConnections: [ + { + name: name + properties: { + privateLinkServiceId: searchService.id + groupIds: [ + privateEndpoint.?service ?? 'searchService' + ] + } + } ] name: privateEndpoint.?name ?? 'pep-${last(split(searchService.id, '/'))}-${privateEndpoint.?service ?? 'searchService'}-${index}' - serviceResourceId: searchService.id subnetResourceId: privateEndpoint.subnetResourceId location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location lock: privateEndpoint.?lock ?? lock diff --git a/avm/res/search/search-service/main.json b/avm/res/search/search-service/main.json index 4a7b90621d..456a5fa77a 100644 --- a/avm/res/search/search-service/main.json +++ b/avm/res/search/search-service/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "7881856021577467097" + "templateHash": "6391154387448662965" }, "name": "Search Services", "description": "This module deploys a Search Service.", @@ -684,17 +684,22 @@ }, "mode": "Incremental", "parameters": { - "groupIds": { + "privateLinkServiceConnections": { "value": [ - "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')]" + { + "name": "[parameters('name')]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]", + "groupIds": [ + "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')]" + ] + } + } ] }, "name": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex()))]" }, - "serviceResourceId": { - "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" - }, "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, @@ -743,7 +748,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "13477311172998188302" + "templateHash": "2821141217598568122" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -758,7 +763,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -882,6 +887,89 @@ }, "nullable": true }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, "customDnsConfigType": { "type": "array", "items": { @@ -920,12 +1008,6 @@ "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "serviceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource that needs to be connected to the network." - } - }, "applicationSecurityGroupResourceIds": { "type": "array", "nullable": true, @@ -946,12 +1028,6 @@ "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." } }, - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." - } - }, "privateDnsZoneGroupName": { "type": "string", "nullable": true, @@ -982,7 +1058,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -999,10 +1075,15 @@ } }, "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." + "description": "Optional. A grouping of information about the connection to the remote resource." } }, "enableTelemetry": { @@ -1032,7 +1113,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.2.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1068,15 +1149,7 @@ "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": [ - { - "name": "[parameters('name')]", - "properties": { - "privateLinkServiceId": "[parameters('serviceResourceId')]", - "groupIds": "[parameters('groupIds')]" - } - } - ], + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", "subnet": { "id": "[parameters('subnetResourceId')]" } @@ -1106,7 +1179,7 @@ "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/sql/server/README.md b/avm/res/sql/server/README.md index 6136d9ae44..a13ba10626 100644 --- a/avm/res/sql/server/README.md +++ b/avm/res/sql/server/README.md @@ -526,6 +526,24 @@ module server 'br/public:avm/res/sql/server:' = { location: '' privateEndpoints: [ { + customDnsConfigs: [ + { + fqdn: 'abc.sqlServer.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'sqlServer' + memberName: 'sqlServer' + privateIPAddress: '10.0.0.10' + } + } + ] privateDnsZoneResourceIds: [ '' ] @@ -575,6 +593,24 @@ module server 'br/public:avm/res/sql/server:' = { "privateEndpoints": { "value": [ { + "customDnsConfigs": [ + { + "fqdn": "abc.sqlServer.com", + "ipAddresses": [ + "10.0.0.10" + ] + } + ], + "ipConfigurations": [ + { + "name": "myIPconfig", + "properties": { + "groupId": "sqlServer", + "memberName": "sqlServer", + "privateIPAddress": "10.0.0.10" + } + } + ], "privateDnsZoneResourceIds": [ "" ], @@ -1307,7 +1343,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`lock`](#parameter-privateendpointslock) | No | object | Optional. Specify the type of lock. | | [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | No | array | Optional. Manual PrivateLink Service Connections. | | [`name`](#parameter-privateendpointsname) | No | string | Optional. The name of the private endpoint. | -| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | No | string | Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. | +| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | No | string | Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | No | array | Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | array | Optional. Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | No | string | Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | @@ -1330,19 +1366,19 @@ Optional. Custom DNS configurations. | Name | Required | Type | Description | | :-- | :-- | :--| :-- | -| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | No | string | Required. Fqdn that resolves to private endpoint ip address. | -| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | Yes | array | Required. A list of private ip addresses of the private endpoint. | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | No | string | Required. Fqdn that resolves to private endpoint IP address. | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | Yes | array | Required. A list of private IP addresses of the private endpoint. | ### Parameter: `privateEndpoints.customDnsConfigs.fqdn` -Required. Fqdn that resolves to private endpoint ip address. +Required. Fqdn that resolves to private endpoint IP address. - Required: No - Type: string ### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` -Required. A list of private ip addresses of the private endpoint. +Required. A list of private IP addresses of the private endpoint. - Required: Yes - Type: array @@ -1392,7 +1428,7 @@ Required. Properties of private endpoint IP configurations. | :-- | :-- | :--| :-- | | [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | Yes | string | Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. | | [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | Yes | string | Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. | -| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | Yes | string | Required. A private ip address obtained from the private endpoint's subnet. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | Yes | string | Required. A private IP address obtained from the private endpoint's subnet. | ### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` @@ -1410,7 +1446,7 @@ Required. The member name of a group obtained from the remote resource that this ### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` -Required. A private ip address obtained from the private endpoint's subnet. +Required. A private IP address obtained from the private endpoint's subnet. - Required: Yes - Type: string @@ -1447,7 +1483,7 @@ Optional. The name of the private endpoint. ### Parameter: `privateEndpoints.privateDnsZoneGroupName` -Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. +Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. - Required: No - Type: string @@ -1629,7 +1665,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/private-endpoint:0.2.1` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.3.1` | Remote reference | ## Notes diff --git a/avm/res/sql/server/main.bicep b/avm/res/sql/server/main.bicep index ed6d64e517..32be5e38be 100644 --- a/avm/res/sql/server/main.bicep +++ b/avm/res/sql/server/main.bicep @@ -234,14 +234,21 @@ module server_elasticPools 'elastic-pool/main.bicep' = [for (elasticPool, index) } }] -module server_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.2.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { +module server_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-server-PrivateEndpoint-${index}' params: { - groupIds: [ - privateEndpoint.?service ?? 'sqlServer' + privateLinkServiceConnections: [ + { + name: name + properties: { + privateLinkServiceId: server.id + groupIds: [ + privateEndpoint.?service ?? 'sqlServer' + ] + } + } ] name: privateEndpoint.?name ?? 'pep-${last(split(server.id, '/'))}-${privateEndpoint.?service ?? 'sqlServer'}-${index}' - serviceResourceId: server.id subnetResourceId: privateEndpoint.subnetResourceId location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location lock: privateEndpoint.?lock ?? lock @@ -392,6 +399,7 @@ type roleAssignmentType = { }[]? type privateEndpointType = { + @description('Optional. The name of the private endpoint.') name: string? @@ -404,7 +412,7 @@ type privateEndpointType = { @description('Required. Resource ID of the subnet where the endpoint needs to be created.') subnetResourceId: string - @description('Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided.') + @description('Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided.') privateDnsZoneGroupName: string? @description('Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones.') @@ -412,10 +420,10 @@ type privateEndpointType = { @description('Optional. Custom DNS configurations.') customDnsConfigs: { - @description('Required. Fqdn that resolves to private endpoint ip address.') + @description('Required. Fqdn that resolves to private endpoint IP address.') fqdn: string? - @description('Required. A list of private ip addresses of the private endpoint.') + @description('Required. A list of private IP addresses of the private endpoint.') ipAddresses: string[] }[]? @@ -432,7 +440,7 @@ type privateEndpointType = { @description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to.') memberName: string - @description('Required. A private ip address obtained from the private endpoint\'s subnet.') + @description('Required. A private IP address obtained from the private endpoint\'s subnet.') privateIPAddress: string } }[]? diff --git a/avm/res/sql/server/main.json b/avm/res/sql/server/main.json index 4ae2fd096c..2e5b06fdd3 100644 --- a/avm/res/sql/server/main.json +++ b/avm/res/sql/server/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "11876144653623707899" + "templateHash": "14112506919364586281" }, "name": "Azure SQL Servers", "description": "This module deploys an Azure SQL Server.", @@ -163,7 +163,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." } }, "privateDnsZoneResourceIds": { @@ -185,7 +185,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." + "description": "Required. Fqdn that resolves to private endpoint IP address." } }, "ipAddresses": { @@ -194,7 +194,7 @@ "type": "string" }, "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." + "description": "Required. A list of private IP addresses of the private endpoint." } } } @@ -233,7 +233,7 @@ "privateIPAddress": { "type": "string", "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." + "description": "Required. A private IP address obtained from the private endpoint's subnet." } } }, @@ -1560,17 +1560,22 @@ }, "mode": "Incremental", "parameters": { - "groupIds": { + "privateLinkServiceConnections": { "value": [ - "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sqlServer')]" + { + "name": "[parameters('name')]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.Sql/servers', parameters('name'))]", + "groupIds": [ + "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sqlServer')]" + ] + } + } ] }, "name": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Sql/servers', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sqlServer'), copyIndex()))]" }, - "serviceResourceId": { - "value": "[resourceId('Microsoft.Sql/servers', parameters('name'))]" - }, "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, @@ -1619,7 +1624,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "13477311172998188302" + "templateHash": "2821141217598568122" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -1634,7 +1639,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -1758,6 +1763,89 @@ }, "nullable": true }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, "customDnsConfigType": { "type": "array", "items": { @@ -1796,12 +1884,6 @@ "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "serviceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource that needs to be connected to the network." - } - }, "applicationSecurityGroupResourceIds": { "type": "array", "nullable": true, @@ -1822,12 +1904,6 @@ "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." } }, - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." - } - }, "privateDnsZoneGroupName": { "type": "string", "nullable": true, @@ -1858,7 +1934,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { - "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -1875,10 +1951,15 @@ } }, "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." + "description": "Optional. A grouping of information about the connection to the remote resource." } }, "enableTelemetry": { @@ -1908,7 +1989,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.2.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1944,15 +2025,7 @@ "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": [ - { - "name": "[parameters('name')]", - "properties": { - "privateLinkServiceId": "[parameters('serviceResourceId')]", - "groupIds": "[parameters('groupIds')]" - } - } - ], + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", "subnet": { "id": "[parameters('subnetResourceId')]" } @@ -1982,7 +2055,7 @@ "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", diff --git a/avm/res/sql/server/tests/e2e/pe/main.test.bicep b/avm/res/sql/server/tests/e2e/pe/main.test.bicep index cf2f89b0ac..c407701e97 100644 --- a/avm/res/sql/server/tests/e2e/pe/main.test.bicep +++ b/avm/res/sql/server/tests/e2e/pe/main.test.bicep @@ -67,6 +67,24 @@ module testDeployment '../../../main.bicep' = { Environment: 'Non-Prod' Role: 'DeploymentValidation' } + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'sqlServer' + memberName: 'sqlServer' + privateIPAddress: '10.0.0.10' + } + } + ] + customDnsConfigs: [ + { + fqdn: 'abc.sqlServer.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] } ] tags: { From 960bd21988f83d4bfb167dcab5951d384360f8f9 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 1 Dec 2023 07:39:36 +0100 Subject: [PATCH 22/22] feat: Added routeType type (#677) ## Description Added a new user-defined type called `routeType`. | Pipeline | | - | | [![avm.res.network.route-table](https://github.com/johnlokerse/bicep-registry-modules/actions/workflows/avm.res.network.route-table.yml/badge.svg?branch=update%2Frtr-type&event=workflow_dispatch)](https://github.com/johnlokerse/bicep-registry-modules/actions/workflows/avm.res.network.route-table.yml) | --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/network/route-table/README.md | 59 ++++++++++++++++++++-- avm/res/network/route-table/main.bicep | 23 ++++++++- avm/res/network/route-table/main.json | 63 ++++++++++++++++++++++-- avm/res/network/route-table/version.json | 4 +- 4 files changed, 137 insertions(+), 12 deletions(-) diff --git a/avm/res/network/route-table/README.md b/avm/res/network/route-table/README.md index 1c857e3d5e..cfe9c7623e 100644 --- a/avm/res/network/route-table/README.md +++ b/avm/res/network/route-table/README.md @@ -316,7 +316,7 @@ module routeTable 'br/public:avm/res/network/route-table:' = { | [`location`](#parameter-location) | string | Location for all resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | | [`roleAssignments`](#parameter-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'. | -| [`routes`](#parameter-routes) | array | An Array of Routes to be established within the hub route table. | +| [`routes`](#parameter-routes) | array | An array of routes to be established within the hub route table. | | [`tags`](#parameter-tags) | object | Tags of the resource. | ### Parameter: `disableBgpRoutePropagation` @@ -443,10 +443,63 @@ Required. The name of the role to assign. If it cannot be found you can specify ### Parameter: `routes` -An Array of Routes to be established within the hub route table. +An array of routes to be established within the hub route table. - Required: No - Type: array -- Default: `[]` + + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`name`](#parameter-routesname) | Yes | string | Required. Name of the route. | +| [`properties`](#parameter-routesproperties) | Yes | object | | + +### Parameter: `routes.name` + +Required. Name of the route. + +- Required: Yes +- Type: string + +### Parameter: `routes.properties` +- Required: Yes +- Type: object + +| Name | Required | Type | Description | +| :-- | :-- | :--| :-- | +| [`addressPrefix`](#parameter-routespropertiesaddressprefix) | No | string | Optional. The destination CIDR to which the route applies. | +| [`hasBgpOverride`](#parameter-routespropertieshasbgpoverride) | No | bool | Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM. | +| [`nextHopIpAddress`](#parameter-routespropertiesnexthopipaddress) | No | string | Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance. | +| [`nextHopType`](#parameter-routespropertiesnexthoptype) | Yes | string | Required. The type of Azure hop the packet should be sent to. | + +### Parameter: `routes.properties.addressPrefix` + +Optional. The destination CIDR to which the route applies. + +- Required: No +- Type: string + +### Parameter: `routes.properties.hasBgpOverride` + +Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM. + +- Required: No +- Type: bool + +### Parameter: `routes.properties.nextHopIpAddress` + +Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance. + +- Required: No +- Type: string + +### Parameter: `routes.properties.nextHopType` + +Required. The type of Azure hop the packet should be sent to. + +- Required: Yes +- Type: string +- Allowed: `[Internet, None, VirtualAppliance, VirtualNetworkGateway, VnetLocal]` + ### Parameter: `tags` diff --git a/avm/res/network/route-table/main.bicep b/avm/res/network/route-table/main.bicep index 2c596f557d..54bb6a9a7b 100644 --- a/avm/res/network/route-table/main.bicep +++ b/avm/res/network/route-table/main.bicep @@ -8,8 +8,8 @@ param name string @description('Optional. Location for all resources.') param location string = resourceGroup().location -@description('Optional. An Array of Routes to be established within the hub route table.') -param routes array = [] +@description('Optional. An array of routes to be established within the hub route table.') +param routes routeType @description('Optional. Switch to disable BGP route propagation.') param disableBgpRoutePropagation bool = false @@ -132,3 +132,22 @@ type roleAssignmentType = { @description('Optional. The Resource Id of the delegated managed identity resource.') delegatedManagedIdentityResourceId: string? }[]? + +type routeType = { + @description('Required. Name of the route.') + name: string + + properties: { + @description('Required. The type of Azure hop the packet should be sent to.') + nextHopType: ('VirtualAppliance' | 'VnetLocal' | 'Internet' | 'VirtualNetworkGateway' | 'None') + + @description('Optional. The destination CIDR to which the route applies.') + addressPrefix: string? + + @description('Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM.') + hasBgpOverride: bool? + + @description('Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance.') + nextHopIpAddress: string? + } +}[]? diff --git a/avm/res/network/route-table/main.json b/avm/res/network/route-table/main.json index 8aa492459b..2dd8d1a934 100644 --- a/avm/res/network/route-table/main.json +++ b/avm/res/network/route-table/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "6317323502554535880" + "version": "0.21.1.54444", + "templateHash": "12297099865892076814" }, "name": "Route Tables", "description": "This module deploys a User Defined Route Table (UDR).", @@ -103,6 +103,60 @@ } }, "nullable": true + }, + "routeType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the route." + } + }, + "properties": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "None", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The type of Azure hop the packet should be sent to." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The destination CIDR to which the route applies." + } + }, + "hasBgpOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM." + } + }, + "nextHopIpAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance." + } + } + } + } + } + }, + "nullable": true } }, "parameters": { @@ -120,10 +174,9 @@ } }, "routes": { - "type": "array", - "defaultValue": [], + "$ref": "#/definitions/routeType", "metadata": { - "description": "Optional. An Array of Routes to be established within the hub route table." + "description": "Optional. An array of routes to be established within the hub route table." } }, "disableBgpRoutePropagation": { diff --git a/avm/res/network/route-table/version.json b/avm/res/network/route-table/version.json index 7fa401bdf7..1c035df49f 100644 --- a/avm/res/network/route-table/version.json +++ b/avm/res/network/route-table/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", + "version": "0.2", "pathFilters": [ "./main.json" ] -} +} \ No newline at end of file