From ce3885f30e16caa8358a8f106e68b11879b2fb83 Mon Sep 17 00:00:00 2001 From: CARMLPipelinePrincipal Date: Sun, 29 Oct 2023 12:06:31 +0000 Subject: [PATCH 1/7] Push updated API Specs file --- utilities/src/apiSpecsList.json | 545 +++++++++++++++++++++++--------- 1 file changed, 401 insertions(+), 144 deletions(-) diff --git a/utilities/src/apiSpecsList.json b/utilities/src/apiSpecsList.json index 3f72b6e1c0..c2f6a20e57 100644 --- a/utilities/src/apiSpecsList.json +++ b/utilities/src/apiSpecsList.json @@ -319,7 +319,8 @@ "2020-01-01", "2020-07-01-preview", "2022-10-01", - "2023-01-01-alpha" + "2023-01-01-alpha", + "2023-09-01-preview" ], "recommendations": [ "2016-05-09-preview", @@ -438,6 +439,9 @@ "2019-03-01-preview", "2019-05-05-preview" ], + "investigations": [ + "2023-06-01-preview" + ], "migrateFromSmartDetection": [ "2021-01-01-preview" ], @@ -526,7 +530,8 @@ }, "Microsoft.ApiCenter": { "operations": [ - "2023-07-01-preview" + "2023-07-01-preview", + "2024-03-01" ], "services": [ "2023-07-01-preview", @@ -2124,6 +2129,9 @@ "reports/evidences": [ "2023-02-15-preview" ], + "reports/scopingConfigurations": [ + "2023-02-15-preview" + ], "reports/snapshots": [ "2022-05-10-beta", "2022-05-10-privatepreview", @@ -2374,7 +2382,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/apiPortals": [ "2022-01-01-preview", @@ -2387,7 +2396,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/apiPortals/domains": [ "2022-01-01-preview", @@ -2400,12 +2410,14 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/apms": [ "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/applicationAccelerators": [ "2022-11-01-preview", @@ -2413,7 +2425,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/applicationAccelerators/customizedAccelerators": [ "2022-11-01-preview", @@ -2421,7 +2434,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/applicationLiveViews": [ "2022-11-01-preview", @@ -2429,7 +2443,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/apps": [ "2020-07-01", @@ -2447,7 +2462,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/apps/bindings": [ "2020-07-01", @@ -2465,7 +2481,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/apps/deployments": [ "2020-07-01", @@ -2483,7 +2500,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/apps/domains": [ "2020-07-01", @@ -2501,13 +2519,15 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/buildServices": [ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/buildServices/agentPools": [ "2022-01-01-preview", @@ -2521,7 +2541,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/buildServices/builders": [ "2022-01-01-preview", @@ -2535,7 +2556,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/buildServices/builders/buildpackBindings": [ "2022-01-01-preview", @@ -2549,7 +2571,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/buildServices/builds": [ "2022-01-01-preview", @@ -2563,7 +2586,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/certificates": [ "2020-07-01", @@ -2581,7 +2605,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/configServers": [ "2020-07-01", @@ -2599,7 +2624,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/configurationServices": [ "2022-01-01-preview", @@ -2613,13 +2639,15 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/containerRegistries": [ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/DevToolPortals": [ "2022-11-01-preview", @@ -2627,12 +2655,14 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/eurekaServers": [ "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/gateways": [ "2022-01-01-preview", @@ -2645,7 +2675,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/gateways/domains": [ "2022-01-01-preview", @@ -2658,7 +2689,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/gateways/routeConfigs": [ "2022-01-01-preview", @@ -2671,7 +2703,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/monitoringSettings": [ "2020-07-01", @@ -2689,7 +2722,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/serviceRegistries": [ "2022-01-01-preview", @@ -2703,7 +2737,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ], "Spring/storages": [ "2021-09-01-preview", @@ -2717,7 +2752,8 @@ "2023-03-01-preview", "2023-05-01-preview", "2023-07-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-11-01-preview" ] }, "Microsoft.ArcNetworking": { @@ -4059,7 +4095,7 @@ "2023-08-01-preview", "2023-09-01-preview" ], - "locations/operationstatuses": [ + "locations/operationStatuses": [ "2020-10-01", "2021-01-01-preview", "2021-07-01-preview", @@ -6995,7 +7031,8 @@ "2023-04-01-preview", "2023-04-15-preview", "2023-09-01-preview", - "2023-10-27-preview" + "2023-10-27-preview", + "2023-11-01" ], "locations": [ "2021-09-15-preview", @@ -7035,6 +7072,9 @@ "2023-09-01-preview", "2023-10-27-preview" ], + "privateAccesses": [ + "2023-10-27-preview" + ], "targets": [ "2021-09-15-preview", "2022-07-01-preview", @@ -7042,7 +7082,8 @@ "2023-04-01-preview", "2023-04-15-preview", "2023-09-01-preview", - "2023-10-27-preview" + "2023-10-27-preview", + "2023-11-01" ], "targets/capabilities": [ "2021-09-15-preview", @@ -7050,7 +7091,9 @@ "2022-10-01-preview", "2023-04-01-preview", "2023-04-15-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-10-27-preview", + "2023-11-01" ] }, "Microsoft.ClassicCompute": { @@ -7781,6 +7824,7 @@ "2022-10-01-preview", "2023-03-01-preview", "2023-03-31", + "2023-04-01", "2023-04-01-preview", "2023-06-01-preview" ], @@ -7794,6 +7838,7 @@ "2022-10-01-preview", "2023-03-01-preview", "2023-03-31", + "2023-04-01", "2023-04-01-preview", "2023-06-01-preview" ], @@ -7803,12 +7848,14 @@ "2022-10-01-preview", "2023-03-01-preview", "2023-03-31", + "2023-04-01", "2023-04-01-preview", "2023-06-01-preview" ], "emailServices/domains/senderUsernames": [ "2023-03-01-preview", "2023-03-31", + "2023-04-01", "2023-04-01-preview", "2023-06-01-preview" ], @@ -10803,6 +10850,10 @@ "2023-09-01", "2023-09-02-preview" ], + "locations/usages": [ + "2023-10-01", + "2023-10-02-preview" + ], "managedClusters": [ "2017-08-31", "2018-03-31", @@ -10930,7 +10981,8 @@ "2023-07-02-preview", "2023-08-01", "2023-08-02-preview", - "2023-09-01" + "2023-09-01", + "2023-09-02-preview" ], "ManagedClusters/eventGridFilters": [ "2021-02-01", @@ -11025,7 +11077,8 @@ "2023-07-02-preview", "2023-08-01", "2023-08-02-preview", - "2023-09-01" + "2023-09-01", + "2023-09-02-preview" ], "managedClusters/privateEndpointConnections": [ "2020-06-01", @@ -11077,7 +11130,8 @@ "2023-07-02-preview", "2023-08-01", "2023-08-02-preview", - "2023-09-01" + "2023-09-01", + "2023-09-02-preview" ], "managedClusters/trustedAccessRoleBindings": [ "2022-04-02-preview", @@ -11097,7 +11151,8 @@ "2023-06-02-preview", "2023-07-02-preview", "2023-08-02-preview", - "2023-09-01" + "2023-09-01", + "2023-09-02-preview" ], "managedclustersnapshots": [ "2022-02-02-preview", @@ -13500,18 +13555,21 @@ "flexibleServers/administrators": [ "2021-12-01-preview", "2022-01-01", - "2023-06-01-preview" + "2023-06-01-preview", + "2023-06-30" ], "flexibleServers/backups": [ "2021-12-01-preview", "2022-01-01", "2022-09-30-preview", - "2023-06-01-preview" + "2023-06-01-preview", + "2023-06-30" ], "flexibleServers/configurations": [ "2021-12-01-preview", "2022-01-01", - "2023-06-01-preview" + "2023-06-01-preview", + "2023-06-30" ], "flexibleServers/databases": [ "2020-07-01-preview", @@ -13520,7 +13578,8 @@ "2021-05-01-preview", "2021-12-01-preview", "2022-01-01", - "2023-06-01-preview" + "2023-06-01-preview", + "2023-06-30" ], "flexibleServers/firewallRules": [ "2020-07-01-preview", @@ -13529,7 +13588,8 @@ "2021-05-01-preview", "2021-12-01-preview", "2022-01-01", - "2023-06-01-preview" + "2023-06-01-preview", + "2023-06-30" ], "flexibleServers/keys": [ "2020-07-01-preview", @@ -14185,7 +14245,8 @@ "2022-12-09-privatepreview", "2023-03-21-privatepreview", "2023-07-07-preview", - "2023-09-05" + "2023-09-05", + "2023-10-04-preview" ], "applicationGroups": [ "2019-01-23-preview", @@ -14213,7 +14274,8 @@ "2022-12-09-privatepreview", "2023-03-21-privatepreview", "2023-07-07-preview", - "2023-09-05" + "2023-09-05", + "2023-10-04-preview" ], "applicationGroups/applications": [ "2019-01-23-preview", @@ -14241,7 +14303,8 @@ "2022-12-09-privatepreview", "2023-03-21-privatepreview", "2023-07-07-preview", - "2023-09-05" + "2023-09-05", + "2023-10-04-preview" ], "applicationgroups/desktops": [ "2019-01-23-preview", @@ -14269,7 +14332,8 @@ "2022-12-09-privatepreview", "2023-03-21-privatepreview", "2023-07-07-preview", - "2023-09-05" + "2023-09-05", + "2023-10-04-preview" ], "applicationgroups/startmenuitems": [ "2019-01-23-preview", @@ -14297,7 +14361,8 @@ "2022-12-09-privatepreview", "2023-03-21-privatepreview", "2023-07-07-preview", - "2023-09-05" + "2023-09-05", + "2023-10-04-preview" ], "hostPools": [ "2019-01-23-preview", @@ -14325,7 +14390,8 @@ "2022-12-09-privatepreview", "2023-03-21-privatepreview", "2023-07-07-preview", - "2023-09-05" + "2023-09-05", + "2023-10-04-preview" ], "hostPools/msixPackages": [ "2019-01-23-preview", @@ -14353,7 +14419,8 @@ "2022-12-09-privatepreview", "2023-03-21-privatepreview", "2023-07-07-preview", - "2023-09-05" + "2023-09-05", + "2023-10-04-preview" ], "hostPools/privateEndpointConnections": [ "2021-04-01-preview", @@ -14390,7 +14457,8 @@ "2022-12-09-privatepreview", "2023-03-21-privatepreview", "2023-07-07-preview", - "2023-09-05" + "2023-09-05", + "2023-10-04-preview" ], "hostpools/sessionhosts/usersessions": [ "2019-01-23-preview", @@ -14418,7 +14486,8 @@ "2022-12-09-privatepreview", "2023-03-21-privatepreview", "2023-07-07-preview", - "2023-09-05" + "2023-09-05", + "2023-10-04-preview" ], "hostpools/usersessions": [ "2019-01-23-preview", @@ -14446,7 +14515,8 @@ "2022-12-09-privatepreview", "2023-03-21-privatepreview", "2023-07-07-preview", - "2023-09-05" + "2023-09-05", + "2023-10-04-preview" ], "operations": [ "2019-01-23-preview", @@ -14484,7 +14554,8 @@ "2023-05-15-privatepreview", "2023-05-18-privatepreview", "2023-07-07-preview", - "2023-09-05" + "2023-09-05", + "2023-10-04-preview" ], "scalingPlans": [ "2019-01-23-preview", @@ -14512,7 +14583,8 @@ "2022-12-09-privatepreview", "2023-03-21-privatepreview", "2023-07-07-preview", - "2023-09-05" + "2023-09-05", + "2023-10-04-preview" ], "scalingPlans/personalSchedules": [ "2023-07-07-preview", @@ -14551,7 +14623,8 @@ "2022-12-09-privatepreview", "2023-03-21-privatepreview", "2023-07-07-preview", - "2023-09-05" + "2023-09-05", + "2023-10-04-preview" ], "workspaces/privateEndpointConnections": [ "2021-04-01-preview", @@ -14909,6 +14982,14 @@ "2023-08-01" ] }, + "Microsoft.DeviceRegistry": { + "assetEndpointProfiles": [ + "2023-11-01-preview" + ], + "assets": [ + "2023-11-01-preview" + ] + }, "Microsoft.Devices": { "checkNameAvailability": [ "2015-08-15-preview", @@ -15661,7 +15742,9 @@ "2023-03-15-preview", "2023-04-15", "2023-09-15", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15", + "2023-11-15-preview" ], "cassandraClusters/dataCenters": [ "2021-03-01-preview", @@ -15721,7 +15804,9 @@ "2023-03-15-preview", "2023-04-15", "2023-09-15", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15", + "2023-11-15-preview" ], "databaseAccounts": [ "2014-04-01", @@ -15760,7 +15845,9 @@ "2023-03-15-preview", "2023-04-15", "2023-09-15", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15", + "2023-11-15-preview" ], "databaseAccounts/apis/databases": [ "2014-04-01", @@ -16043,7 +16130,9 @@ "2023-03-15-preview", "2023-04-15", "2023-09-15", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15", + "2023-11-15-preview" ], "databaseAccounts/graphs": [ "2021-07-01-preview", @@ -16813,13 +16902,16 @@ "2023-03-15-preview", "2023-04-15", "2023-09-15", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15", + "2023-11-15-preview" ], "locations/checkMongoClusterNameAvailability": [ "2022-10-15-preview", "2023-03-01-preview", "2023-03-15-preview", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15-preview" ], "locations/deleteVirtualNetworkOrSubnets": [ "2014-04-01", @@ -16858,19 +16950,23 @@ "2023-03-15-preview", "2023-04-15", "2023-09-15", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15", + "2023-11-15-preview" ], "locations/mongoClusterAzureAsyncOperation": [ "2022-10-15-preview", "2023-03-01-preview", "2023-03-15-preview", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15-preview" ], "locations/mongoClusterOperationResults": [ "2022-10-15-preview", "2023-03-01-preview", "2023-03-15-preview", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15-preview" ], "locations/notifyNetworkSecurityPerimeterUpdatesAvailable": [ "2022-08-15", @@ -16882,7 +16978,9 @@ "2023-03-15-preview", "2023-04-15", "2023-09-15", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15", + "2023-11-15-preview" ], "locations/operationResults": [ "2014-04-01", @@ -16921,7 +17019,9 @@ "2023-03-15-preview", "2023-04-15", "2023-09-15", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15", + "2023-11-15-preview" ], "locations/operationsStatus": [ "2014-04-01", @@ -16960,7 +17060,9 @@ "2023-03-15-preview", "2023-04-15", "2023-09-15", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15", + "2023-11-15-preview" ], "locations/restorableDatabaseAccounts": [ "2020-06-01-preview", @@ -16984,13 +17086,16 @@ "2023-03-15-preview", "2023-04-15", "2023-09-15", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15", + "2023-11-15-preview" ], "mongoClusters": [ "2022-10-15-preview", "2023-03-01-preview", "2023-03-15-preview", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15-preview" ], "mongoClusters/firewallRules": [ "2023-03-01-preview", @@ -17034,7 +17139,9 @@ "2023-03-15-preview", "2023-04-15", "2023-09-15", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15", + "2023-11-15-preview" ], "operations": [ "2014-04-01", @@ -17073,7 +17180,9 @@ "2023-03-15-preview", "2023-04-15", "2023-09-15", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15", + "2023-11-15-preview" ], "operationsStatus": [ "2014-04-01", @@ -17112,7 +17221,9 @@ "2023-03-15-preview", "2023-04-15", "2023-09-15", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15", + "2023-11-15-preview" ], "restorableDatabaseAccounts": [ "2020-06-01-preview", @@ -17136,7 +17247,9 @@ "2023-03-15-preview", "2023-04-15", "2023-09-15", - "2023-09-15-preview" + "2023-09-15-preview", + "2023-11-15", + "2023-11-15-preview" ] }, "Microsoft.DomainRegistration": { @@ -17297,6 +17410,11 @@ "2023-04-01-preview" ] }, + "Microsoft.EdgeManagement": { + "locations": [ + "2023-09-01-preview" + ] + }, "Microsoft.EdgeMarketPlace": { "operations": [ "2023-04-01-preview", @@ -19247,6 +19365,9 @@ ] }, "Microsoft.HybridContainerService": { + "kubernetesVersions": [ + "2023-11-15-preview" + ], "Locations": [ "2021-08-01-preview", "2021-09-01-preview", @@ -19274,6 +19395,15 @@ "2023-11-01", "2023-11-15-preview" ], + "provisionedClusterInstances": [ + "2023-11-15-preview" + ], + "provisionedClusterInstances/agentPools": [ + "2023-11-15-preview" + ], + "provisionedClusterInstances/hybridIdentityMetadata": [ + "2023-11-15-preview" + ], "provisionedClusters": [ "2021-08-01-preview", "2021-09-01-preview", @@ -19295,13 +19425,17 @@ "provisionedClusters/upgradeProfiles": [ "2022-09-01-preview" ], + "skus": [ + "2023-11-15-preview" + ], "storageSpaces": [ "2022-05-01-preview", "2022-09-01-preview" ], "virtualNetworks": [ "2022-05-01-preview", - "2022-09-01-preview" + "2022-09-01-preview", + "2023-11-15-preview" ] }, "Microsoft.HybridData": { @@ -19319,6 +19453,9 @@ ] }, "Microsoft.HybridNetwork": { + "configurationGroupValues": [ + "2023-09-01" + ], "devices": [ "2020-01-01-preview", "2021-05-01", @@ -19344,7 +19481,8 @@ "2021-06-01-privatepreview", "2022-01-01-preview", "2022-09-01-preview", - "2023-01-01" + "2023-01-01", + "2023-09-01" ], "networkFunctions/components": [ "2022-09-01-preview", @@ -19364,19 +19502,39 @@ "2023-04-01-preview" ], "publishers": [ - "2023-01-01" + "2023-01-01", + "2023-09-01" ], "publishers/artifactStores": [ - "2023-01-01" + "2023-01-01", + "2023-09-01" ], "publishers/artifactStores/artifactManifests": [ - "2023-01-01" + "2023-01-01", + "2023-09-01" + ], + "publishers/configurationGroupSchemas": [ + "2023-09-01" ], "publishers/networkFunctionDefinitionGroups": [ - "2023-01-01" + "2023-01-01", + "2023-09-01" ], "publishers/networkFunctionDefinitionGroups/networkFunctionDefinitionVersions": [ - "2023-01-01" + "2023-01-01", + "2023-09-01" + ], + "publishers/networkServiceDesignGroups": [ + "2023-09-01" + ], + "publishers/networkServiceDesignGroups/networkServiceDesignVersions": [ + "2023-09-01" + ], + "siteNetworkServices": [ + "2023-09-01" + ], + "sites": [ + "2023-09-01" ], "vendors": [ "2020-01-01-preview", @@ -19925,6 +20083,21 @@ ], "operations": [ "2023-11-14-preview" + ], + "spaces": [ + "2023-11-14-preview" + ], + "spaces/applications": [ + "2023-11-14-preview" + ], + "spaces/applications/businessProcesses": [ + "2023-11-14-preview" + ], + "spaces/applications/resources": [ + "2023-11-14-preview" + ], + "spaces/infrastructureResources": [ + "2023-11-14-preview" ] }, "Microsoft.Intune": { @@ -20406,7 +20579,8 @@ "2021-04-01-preview", "2021-10-01", "2022-05-01-preview", - "2022-10-01-preview" + "2022-10-01-preview", + "2023-11-01-preview" ], "locations": [ "2020-01-01-preview", @@ -23452,7 +23626,8 @@ "2022-12-01-privatepreview", "2023-06-01", "2023-07-01-preview", - "2023-09-01" + "2023-09-01", + "2023-10-01-preview" ], "Locations/OperationStatuses": [ "2022-04-01-preview", @@ -23460,7 +23635,8 @@ "2022-12-01-privatepreview", "2023-06-01", "2023-07-01-preview", - "2023-09-01" + "2023-09-01", + "2023-10-01-preview" ], "mobileNetworks": [ "2022-03-01-preview", @@ -23510,7 +23686,8 @@ "2022-12-01-privatepreview", "2023-06-01", "2023-07-01-preview", - "2023-09-01" + "2023-09-01", + "2023-10-01-preview" ], "packetCoreControlPlanes": [ "2022-03-01-preview", @@ -23547,7 +23724,8 @@ "2022-12-01-privatepreview", "2023-06-01", "2023-07-01-preview", - "2023-09-01" + "2023-09-01", + "2023-10-01-preview" ], "simGroups": [ "2022-04-01-preview", @@ -23568,18 +23746,21 @@ "Microsoft.MobilePacketCore": { "Locations": [ "2023-04-15-preview", - "2023-05-15-preview" + "2023-05-15-preview", + "2023-10-15" ], "Locations/OperationStatuses": [ "2023-04-15-preview", - "2023-05-15-preview" + "2023-05-15-preview", + "2023-10-15" ], "networkFunctions": [ "2023-05-15-preview" ], "Operations": [ "2023-04-15-preview", - "2023-05-15-preview" + "2023-05-15-preview", + "2023-10-15" ] }, "Microsoft.ModSimWorkbench": { @@ -23604,6 +23785,10 @@ "2023-04-01", "2023-04-03" ], + "locations/locationOperationStatuses": [ + "2021-06-03-preview", + "2023-04-03" + ], "locations/operationResults": [ "2021-06-03-preview", "2023-04-03" @@ -27861,19 +28046,29 @@ ], "networkSecurityPerimeters": [ "2021-02-01-preview", - "2021-03-01-preview" + "2021-03-01-preview", + "2023-07-01-preview", + "2023-08-01-preview" ], "networkSecurityPerimeters/links": [ - "2021-02-01-preview" + "2021-02-01-preview", + "2023-07-01-preview", + "2023-08-01-preview" ], "networkSecurityPerimeters/profiles": [ - "2021-02-01-preview" + "2021-02-01-preview", + "2023-07-01-preview", + "2023-08-01-preview" ], "networkSecurityPerimeters/profiles/accessRules": [ - "2021-02-01-preview" + "2021-02-01-preview", + "2023-07-01-preview", + "2023-08-01-preview" ], "networkSecurityPerimeters/resourceAssociations": [ - "2021-02-01-preview" + "2021-02-01-preview", + "2023-07-01-preview", + "2023-08-01-preview" ], "networkVirtualAppliances": [ "2019-12-01", @@ -32587,6 +32782,9 @@ "2021-10-31-preview", "2022-04-15-preview", "2022-10-27" + ], + "telemetryconfig": [ + "2022-10-27" ] }, "Microsoft.ResourceGraph": { @@ -33018,6 +33216,9 @@ "locations/deploymentStackOperationStatus": [ "2022-08-01-preview" ], + "mobobrokers": [ + "2023-06-01-preview" + ], "notifyResourceJobs": [ "2018-02-01", "2018-05-01", @@ -33538,17 +33739,20 @@ "locations": [ "2020-06-05-preview", "2022-05-21-preview", - "2023-04-01-preview" + "2023-04-01-preview", + "2023-10-07" ], "Locations/OperationStatuses": [ "2020-06-05-preview", "2022-05-21-preview", - "2023-04-01-preview" + "2023-04-01-preview", + "2023-10-07" ], "operations": [ "2020-06-05-preview", "2022-05-21-preview", - "2023-04-01-preview" + "2023-04-01-preview", + "2023-10-07" ], "virtualMachineInstances": [ "2023-04-01-preview", @@ -33609,7 +33813,8 @@ "2020-08-01-Preview", "2021-04-01-Preview", "2021-06-06-Preview", - "2022-09-01" + "2022-09-01", + "2023-11-01" ], "checkServiceNameAvailability": [ "2014-07-31-Preview", @@ -33624,6 +33829,9 @@ "locations/operationResults": [ "2021-06-06-Preview" ], + "locations/usages": [ + "2023-11-01" + ], "operations": [ "2015-02-28", "2015-08-19", @@ -33633,7 +33841,8 @@ "2020-08-01-Preview", "2021-04-01-Preview", "2021-06-06-Preview", - "2022-09-01" + "2022-09-01", + "2023-11-01" ], "resourceHealthMetadata": [ "2015-08-19", @@ -33643,7 +33852,8 @@ "2020-08-01-Preview", "2021-04-01-Preview", "2021-06-06-Preview", - "2022-09-01" + "2022-09-01", + "2023-11-01" ], "searchServices": [ "2014-07-31-Preview", @@ -33937,7 +34147,8 @@ "2021-12-01-preview", "2022-05-01-preview", "2022-08-01-preview", - "2023-03-01-preview" + "2023-03-01-preview", + "2023-10-01-preview" ], "securityConnectors/devops": [ "2023-09-01-preview" @@ -39033,7 +39244,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "managedInstances/databases": [ "2017-03-01-preview", @@ -39095,7 +39307,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "managedInstances/databases/ledgerDigestUploads": [ "2022-08-01-preview", @@ -39117,7 +39330,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "managedInstances/databases/securityAlertPolicies": [ "2017-03-01-preview", @@ -39133,7 +39347,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "managedInstances/databases/transparentDataEncryption": [ "2020-02-02-preview", @@ -39148,7 +39363,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "managedInstances/databases/vulnerabilityAssessments": [ "2017-03-01-preview", @@ -39184,7 +39400,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "managedInstances/distributedAvailabilityGroups": [ "2021-05-01-preview", @@ -39195,7 +39412,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "managedInstances/dnsAliases": [ "2021-11-01", @@ -39212,7 +39430,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "managedInstances/encryptionProtector": [ "2017-10-01-preview", @@ -39228,7 +39447,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "managedInstances/keys": [ "2017-10-01-preview", @@ -39244,7 +39464,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "managedInstances/metricDefinitions": [ "2017-03-01-preview", @@ -39299,7 +39520,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "managedInstances/recoverableDatabases": [ "2017-10-01-preview", @@ -39334,7 +39556,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "managedInstances/securityAlertPolicies": [ "2017-03-01-preview", @@ -39350,12 +39573,14 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "managedInstances/serverConfigurationOptions": [ "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "managedInstances/serverTrustCertificates": [ "2021-05-01-preview", @@ -39366,7 +39591,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "managedInstances/sqlAgent": [ "2018-06-01", @@ -39607,7 +39833,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/communicationLinks": [ "2014-01-01", @@ -39867,7 +40094,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/databases/extensions": [ "2014-01-01", @@ -39884,7 +40112,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/databases/geoBackupPolicies": [ "2014-01-01", @@ -39936,7 +40165,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/databases/metricDefinitions": [ "2014-01-01", @@ -39968,6 +40198,9 @@ "2023-02-01-preview", "2023-05-01-preview" ], + "servers/databases/replicationLinks": [ + "2023-05-01-preview" + ], "servers/databases/schemas/tables/columns/sensitivityLabels": [ "2017-03-01-preview", "2020-02-02-preview", @@ -39982,7 +40215,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/databases/securityAlertPolicies": [ "2014-01-01", @@ -40018,14 +40252,16 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/databases/sqlVulnerabilityAssessments/baselines/rules": [ "2022-02-01-preview", "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/databases/syncGroups": [ "2015-05-01-preview", @@ -40151,7 +40387,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/databases/VulnerabilityAssessmentScans": [ "2015-05-01-preview", @@ -40226,7 +40463,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/databaseSecurityPolicies": [ "2014-01-01", @@ -40434,7 +40672,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/import": [ "2014-01-01", @@ -40468,7 +40707,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/jobAccounts": [ "2015-05-01-preview" @@ -40507,7 +40747,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/jobAgents/jobs": [ "2017-03-01-preview", @@ -40586,7 +40827,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/keys": [ "2015-05-01-preview", @@ -40624,7 +40866,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/privateEndpointConnections": [ "2018-06-01-preview", @@ -40640,7 +40883,8 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/recommendedElasticPools": [ "2014-01-01", @@ -40726,14 +40970,16 @@ "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/sqlVulnerabilityAssessments/baselines/rules": [ "2022-02-01-preview", "2022-05-01-preview", "2022-08-01-preview", "2022-11-01-preview", - "2023-02-01-preview" + "2023-02-01-preview", + "2023-05-01-preview" ], "servers/syncAgents": [ "2015-05-01-preview", @@ -43079,7 +43325,8 @@ "2022-08-01", "2023-06-02-preview", "2023-08-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2024-01-01" ], "locations": [ "2021-10-18-preview", @@ -43090,7 +43337,8 @@ "2022-08-01", "2023-06-02-preview", "2023-08-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2024-01-01" ], "locations/classicaccounts": [ "2021-10-27-preview", @@ -43107,7 +43355,8 @@ "2022-07-20-preview", "2022-08-01", "2023-06-02-preview", - "2023-08-01-preview" + "2023-08-01-preview", + "2024-01-01" ], "locations/userclassicaccounts": [ "2021-10-27-preview", @@ -43125,7 +43374,8 @@ "2022-08-01", "2023-06-02-preview", "2023-08-01-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2024-01-01" ] }, "Microsoft.VirtualMachineImages": { @@ -43246,26 +43496,30 @@ "2023-01-31", "2023-04-03", "2023-07-13-preview", - "2023-09-01" + "2023-09-01", + "2023-09-21" ], "locations/checkNameAvailability": [ "2023-01-31", "2023-04-03", "2023-07-13-preview", - "2023-09-01" + "2023-09-01", + "2023-09-21" ], "Operations": [ "2023-01-31", "2023-04-03", "2023-07-13-preview", - "2023-09-01" + "2023-09-01", + "2023-09-21" ], "registeredSubscriptions": [ "2022-12-01-preview", "2023-01-31", "2023-04-03", "2023-07-13-preview", - "2023-09-01" + "2023-09-01", + "2023-09-21" ] }, "Microsoft.VSOnline": { @@ -45668,17 +45922,20 @@ "locations": [ "2022-08-29", "2022-08-29-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-10-10-preview" ], "Locations/operationStatuses": [ "2022-08-29", "2022-08-29-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-10-10-preview" ], "operations": [ "2022-08-29", "2022-08-29-preview", - "2023-09-01-preview" + "2023-09-01-preview", + "2023-10-10-preview" ], "registeredSubscriptions": [ "2022-08-29", From f65a57aae1e8f9e348003036d0b7378566e852a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20M=C3=BCller?= Date: Mon, 30 Oct 2023 13:06:56 +0100 Subject: [PATCH 2/7] [Module] Added Microsoft.App/jobs (#4156) * Module App Container Job * add pipelines * temp trigger for new module validation * fix file endings * trigger test * fixed parameter descriptions * update description in main.json * update readme * trigger validation * fix line ending * trigger validation * fix workload profile * add workload profile test * update readme * reduce test serviceShort * fix test * fix dependency * Prepare PR * Fix spelling of ID * Resolved review topics * added new managed identities method --- .azuredevops/modulePipelines/ms.app.jobs.yml | 50 ++ .github/workflows/ms.app.jobs.yml | 84 +++ .../app/job/.test/common/dependencies.bicep | 40 ++ modules/app/job/.test/common/main.test.bicep | 124 ++++ modules/app/job/.test/min/dependencies.bicep | 21 + modules/app/job/.test/min/main.test.bicep | 79 +++ modules/app/job/README.md | 615 ++++++++++++++++++ modules/app/job/main.bicep | 205 ++++++ modules/app/job/main.json | 400 ++++++++++++ modules/app/job/version.json | 7 + 10 files changed, 1625 insertions(+) create mode 100644 .azuredevops/modulePipelines/ms.app.jobs.yml create mode 100644 .github/workflows/ms.app.jobs.yml create mode 100644 modules/app/job/.test/common/dependencies.bicep create mode 100644 modules/app/job/.test/common/main.test.bicep create mode 100644 modules/app/job/.test/min/dependencies.bicep create mode 100644 modules/app/job/.test/min/main.test.bicep create mode 100644 modules/app/job/README.md create mode 100644 modules/app/job/main.bicep create mode 100644 modules/app/job/main.json create mode 100644 modules/app/job/version.json diff --git a/.azuredevops/modulePipelines/ms.app.jobs.yml b/.azuredevops/modulePipelines/ms.app.jobs.yml new file mode 100644 index 0000000000..beedc2bee1 --- /dev/null +++ b/.azuredevops/modulePipelines/ms.app.jobs.yml @@ -0,0 +1,50 @@ +name: 'App - Jobs' + +parameters: + - name: staticValidation + displayName: Execute static validation + type: boolean + default: true + - name: deploymentValidation + displayName: Execute deployment validation + type: boolean + default: true + - name: removeDeployment + displayName: Remove deployed module + type: boolean + default: true + - name: prerelease + displayName: Publish prerelease module + type: boolean + default: false + +pr: none + +trigger: + batch: true + branches: + include: + - main + paths: + include: + - '/.azuredevops/modulePipelines/ms.app.jobs.yml' + - '/.azuredevops/pipelineTemplates/*.yml' + - '/modules/app/job/*' + - '/utilities/pipelines/*' + exclude: + - '/utilities/pipelines/deploymentRemoval/*' + - '/**/*.md' + +variables: + - template: '../../settings.yml' + - group: 'PLATFORM_VARIABLES' + - name: modulePath + value: '/modules/app/job' + +stages: + - template: /.azuredevops/pipelineTemplates/stages.module.yml + parameters: + staticValidation: '${{ parameters.staticValidation }}' + deploymentValidation: '${{ parameters.deploymentValidation }}' + removeDeployment: '${{ parameters.removeDeployment }}' + prerelease: '${{ parameters.prerelease }}' diff --git a/.github/workflows/ms.app.jobs.yml b/.github/workflows/ms.app.jobs.yml new file mode 100644 index 0000000000..bde1eff318 --- /dev/null +++ b/.github/workflows/ms.app.jobs.yml @@ -0,0 +1,84 @@ +name: 'App - Jobs' + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: 'Execute static validation' + required: false + default: true + deploymentValidation: + type: boolean + description: 'Execute deployment validation' + required: false + default: true + removeDeployment: + type: boolean + description: 'Remove deployed module' + required: false + default: true + prerelease: + type: boolean + description: 'Publish prerelease module' + required: false + default: false + push: + branches: + - main + paths: + - '.github/actions/templates/**' + - '.github/workflows/template.module.yml' + - '.github/workflows/ms.app.jobs.yml' + - 'modules/app/job/**' + - 'utilities/pipelines/**' + - '!utilities/pipelines/deploymentRemoval/**' + - '!*/**/README.md' + +env: + modulePath: 'modules/app/job' + workflowPath: '.github/workflows/ms.app.jobs.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/getWorkflowInput + with: + workflowPath: '${{ env.workflowPath}}' + - name: 'Get parameter file paths' + id: get-module-test-file-paths + uses: ./.github/actions/templates/getModuleTestFiles + with: + modulePath: '${{ env.modulePath }}' + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + modulePath: '${{ env.modulePath }}' + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: 'Module' + needs: + - job_initialize_pipeline + uses: ./.github/workflows/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/modules/app/job/.test/common/dependencies.bicep b/modules/app/job/.test/common/dependencies.bicep new file mode 100644 index 0000000000..b03d4aca93 --- /dev/null +++ b/modules/app/job/.test/common/dependencies.bicep @@ -0,0 +1,40 @@ +@description('Required. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Environment for Container Apps to create.') +param managedEnvironmentName string + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the workload profile to create.') +param workloadProfileName string + +resource managedEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { + name: managedEnvironmentName + location: location + properties: { + workloadProfiles: [ + { + name: workloadProfileName + workloadProfileType: 'D4' + maximumCount: 1 + minimumCount: 1 + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2022-01-31-preview' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Managed Environment.') +output managedEnvironmentResourceId string = managedEnvironment.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/modules/app/job/.test/common/main.test.bicep b/modules/app/job/.test/common/main.test.bicep new file mode 100644 index 0000000000..5d608f7db8 --- /dev/null +++ b/modules/app/job/.test/common/main.test.bicep @@ -0,0 +1,124 @@ +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}-app.job-${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 = 'ajcom' + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableDefaultTelemetry bool = true + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '[[namePrefix]]' + +// =========== // +// Deployments // +// =========== // + +// 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)}-paramNested' + params: { + location: location + managedEnvironmentName: 'dep-${namePrefix}-menv-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + workloadProfileName: serviceShort + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + tags: { + 'hidden-title': 'This is visible in the resource name' + Env: 'test' + } + enableDefaultTelemetry: enableDefaultTelemetry + environmentId: nestedDependencies.outputs.managedEnvironmentResourceId + workloadProfileName: serviceShort + location: location + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + secrets: { + secureList: [ + { + name: 'customtest' + value: guid(deployment().name) + } + ] + } + triggerType: 'Manual' + manualTriggerConfig: { + replicaCompletionCount: 1 + parallelism: 1 + } + containers: [ + { + name: 'simple-hello-world-container' + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + resources: { + // workaround as 'float' values are not supported in Bicep, yet the resource providers expects them. Related issue: https://github.com/Azure/bicep/issues/1386 + cpu: json('0.25') + memory: '0.5Gi' + } + probes: [ + { + type: 'Liveness' + httpGet: { + path: '/health' + port: 8080 + httpHeaders: [ + { + name: 'Custom-Header' + value: 'Awesome' + } + ] + } + initialDelaySeconds: 3 + periodSeconds: 3 + } + ] + } + ] + roleAssignments: [ + { + principalId: nestedDependencies.outputs.managedIdentityResourceId + roleDefinitionIdOrName: 'ContainerApp Reader' + principalType: 'ServicePrincipal' + } + ] + } +} diff --git a/modules/app/job/.test/min/dependencies.bicep b/modules/app/job/.test/min/dependencies.bicep new file mode 100644 index 0000000000..bb2af3d0f8 --- /dev/null +++ b/modules/app/job/.test/min/dependencies.bicep @@ -0,0 +1,21 @@ +@description('Required. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Environment to create.') +param managedEnvironmentName string + +resource managedEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { + name: managedEnvironmentName + location: location + properties: { + workloadProfiles: [ + { + workloadProfileType: 'Consumption' + name: 'Consumption' + } + ] + } +} + +@description('The resource ID of the created Managed Environment.') +output managedEnvironmentResourceId string = managedEnvironment.id diff --git a/modules/app/job/.test/min/main.test.bicep b/modules/app/job/.test/min/main.test.bicep new file mode 100644 index 0000000000..b1e06bbb23 --- /dev/null +++ b/modules/app/job/.test/min/main.test.bicep @@ -0,0 +1,79 @@ +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}-app.job-${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 = 'ajmin' + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableDefaultTelemetry bool = true + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '[[namePrefix]]' + +// =========== // +// Deployments // +// =========== // + +// 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)}-paramNested' + params: { + location: location + managedEnvironmentName: 'dep-${namePrefix}-menv-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + tags: { + 'hidden-title': 'This is visible in the resource name' + Env: 'test' + } + enableDefaultTelemetry: enableDefaultTelemetry + environmentId: nestedDependencies.outputs.managedEnvironmentResourceId + location: location + triggerType: 'Manual' + manualTriggerConfig: { + replicaCompletionCount: 1 + parallelism: 1 + } + containers: [ + { + name: 'simple-hello-world-container' + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + resources: { + // workaround as 'float' values are not supported in Bicep, yet the resource providers expects them. Related issue: https://github.com/Azure/bicep/issues/1386 + cpu: json('0.25') + memory: '0.5Gi' + } + } + ] + } +} diff --git a/modules/app/job/README.md b/modules/app/job/README.md new file mode 100644 index 0000000000..5d12efcabe --- /dev/null +++ b/modules/app/job/README.md @@ -0,0 +1,615 @@ +# Container App Jobs `[Microsoft.App/jobs]` + +This module deploys a Container App Job. + +## 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.App/jobs` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.App/2023-05-01/jobs) | +| `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) | + +## 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:bicep/modules/app.job:1.0.0`. + +- [Using large parameter set](#example-1-using-large-parameter-set) +- [Using only defaults](#example-2-using-only-defaults) + +### Example 1: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +
+ +via Bicep module + +```bicep +module job 'br:bicep/modules/app.job:1.0.0' = { + name: '${uniqueString(deployment().name, location)}-test-ajcom' + params: { + // Required parameters + containers: [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + probes: [ + { + httpGet: { + httpHeaders: [ + { + name: 'Custom-Header' + value: 'Awesome' + } + ] + path: '/health' + port: 8080 + } + initialDelaySeconds: 3 + periodSeconds: 3 + type: 'Liveness' + } + ] + resources: { + cpu: '' + memory: '0.5Gi' + } + } + ] + environmentId: '' + name: 'ajcom001' + triggerType: 'Manual' + // Non-required parameters + enableDefaultTelemetry: '' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } + manualTriggerConfig: { + parallelism: 1 + replicaCompletionCount: 1 + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'ContainerApp Reader' + } + ] + secrets: { + secureList: [ + { + name: 'customtest' + value: '' + } + ] + } + tags: { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' + } + workloadProfileName: '' + } +} +``` + +
+

+ +

+ +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 + "containers": { + "value": [ + { + "image": "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest", + "name": "simple-hello-world-container", + "probes": [ + { + "httpGet": { + "httpHeaders": [ + { + "name": "Custom-Header", + "value": "Awesome" + } + ], + "path": "/health", + "port": 8080 + }, + "initialDelaySeconds": 3, + "periodSeconds": 3, + "type": "Liveness" + } + ], + "resources": { + "cpu": "", + "memory": "0.5Gi" + } + } + ] + }, + "environmentId": { + "value": "" + }, + "name": { + "value": "ajcom001" + }, + "triggerType": { + "value": "Manual" + }, + // Non-required parameters + "enableDefaultTelemetry": { + "value": "" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, + "manualTriggerConfig": { + "value": { + "parallelism": 1, + "replicaCompletionCount": 1 + } + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "ContainerApp Reader" + } + ] + }, + "secrets": { + "value": { + "secureList": [ + { + "name": "customtest", + "value": "" + } + ] + } + }, + "tags": { + "value": { + "Env": "test", + "hidden-title": "This is visible in the resource name" + } + }, + "workloadProfileName": { + "value": "" + } + } +} +``` + +
+

+ +### Example 2: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module job 'br:bicep/modules/app.job:1.0.0' = { + name: '${uniqueString(deployment().name, location)}-test-ajmin' + params: { + // Required parameters + containers: [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + resources: { + cpu: '' + memory: '0.5Gi' + } + } + ] + environmentId: '' + name: 'ajmin001' + triggerType: 'Manual' + // Non-required parameters + enableDefaultTelemetry: '' + location: '' + manualTriggerConfig: { + parallelism: 1 + replicaCompletionCount: 1 + } + tags: { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' + } + } +} +``` + +
+

+ +

+ +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 + "containers": { + "value": [ + { + "image": "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest", + "name": "simple-hello-world-container", + "resources": { + "cpu": "", + "memory": "0.5Gi" + } + } + ] + }, + "environmentId": { + "value": "" + }, + "name": { + "value": "ajmin001" + }, + "triggerType": { + "value": "Manual" + }, + // Non-required parameters + "enableDefaultTelemetry": { + "value": "" + }, + "location": { + "value": "" + }, + "manualTriggerConfig": { + "value": { + "parallelism": 1, + "replicaCompletionCount": 1 + } + }, + "tags": { + "value": { + "Env": "test", + "hidden-title": "This is visible in the resource name" + } + } + } +} +``` + +
+

+ + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`containers`](#parameter-containers) | array | List of container definitions for the Container App. | +| [`environmentId`](#parameter-environmentid) | string | Resource ID of environment. | +| [`name`](#parameter-name) | string | Name of the Container App. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableDefaultTelemetry`](#parameter-enabledefaulttelemetry) | bool | Enable telemetry via a Globally Unique Identifier (GUID). | +| [`eventTriggerConfig`](#parameter-eventtriggerconfig) | object | Required if TriggerType is Event. Configuration of an event driven job. | +| [`initContainersTemplate`](#parameter-initcontainerstemplate) | array | List of specialized containers that run before app containers. | +| [`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. | +| [`manualTriggerConfig`](#parameter-manualtriggerconfig) | object | Required if TriggerType is Manual. Configuration of a manual job. | +| [`registries`](#parameter-registries) | array | Collection of private container registry credentials for containers used by the Container app. | +| [`replicaRetryLimit`](#parameter-replicaretrylimit) | int | The maximum number of times a replica can be retried. | +| [`replicaTimeout`](#parameter-replicatimeout) | int | Maximum number of seconds a replica is allowed to run. | +| [`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. | +| [`scheduleTriggerConfig`](#parameter-scheduletriggerconfig) | object | Required if TriggerType is Schedule. Configuration of a schedule based job. | +| [`secrets`](#parameter-secrets) | secureObject | The secrets of the Container App. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`triggerType`](#parameter-triggertype) | string | Trigger type of the job. | +| [`volumes`](#parameter-volumes) | array | List of volume definitions for the Container App. | +| [`workloadProfileName`](#parameter-workloadprofilename) | string | The name of the workload profile to use. | + +### Parameter: `containers` + +List of container definitions for the Container App. +- Required: Yes +- Type: array + +### Parameter: `enableDefaultTelemetry` + +Enable telemetry via a Globally Unique Identifier (GUID). +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `environmentId` + +Resource ID of environment. +- Required: Yes +- Type: string + +### Parameter: `eventTriggerConfig` + +Required if TriggerType is Event. Configuration of an event driven job. +- Required: No +- Type: object +- Default: `{object}` + +### Parameter: `initContainersTemplate` + +List of specialized containers that run before app containers. +- 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. Required if a user assigned identity is used for encryption. | + +### 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 if a user assigned identity is used for encryption. + +- Required: No +- Type: array + +### Parameter: `manualTriggerConfig` + +Required if TriggerType is Manual. Configuration of a manual job. +- Required: No +- Type: object +- Default: `{object}` + +### Parameter: `name` + +Name of the Container App. +- Required: Yes +- Type: string + +### Parameter: `registries` + +Collection of private container registry credentials for containers used by the Container app. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `replicaRetryLimit` + +The maximum number of times a replica can be retried. +- Required: No +- Type: int +- Default: `0` + +### Parameter: `replicaTimeout` + +Maximum number of seconds a replica is allowed to run. +- Required: No +- Type: int +- Default: `1800` + +### 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. +- 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: `scheduleTriggerConfig` + +Required if TriggerType is Schedule. Configuration of a schedule based job. +- Required: No +- Type: object +- Default: `{object}` + +### Parameter: `secrets` + +The secrets of the Container App. +- Required: No +- Type: secureObject +- Default: `{object}` + +### Parameter: `tags` + +Tags of the resource. +- Required: No +- Type: object +- Default: `{object}` + +### Parameter: `triggerType` + +Trigger type of the job. +- Required: Yes +- Type: string +- Allowed: `[Event, Manual, Schedule]` + +### Parameter: `volumes` + +List of volume definitions for the Container App. +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `workloadProfileName` + +The name of the workload profile to use. +- Required: No +- Type: string +- Default: `'Consumption'` + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the Container App Job. | +| `resourceGroupName` | string | The name of the resource group the Container App Job was deployed into. | +| `resourceId` | string | The resource ID of the Container App Job. | +| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | + +## Cross-referenced modules + +_None_ diff --git a/modules/app/job/main.bicep b/modules/app/job/main.bicep new file mode 100644 index 0000000000..75b067268c --- /dev/null +++ b/modules/app/job/main.bicep @@ -0,0 +1,205 @@ +metadata name = 'Container App Jobs' +metadata description = 'This module deploys a Container App Job.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. Name of the Container App.') +param name string + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Required. Resource ID of environment.') +param environmentId string + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Tags of the resource.') +param tags object = {} + +@description('Optional. Collection of private container registry credentials for containers used by the Container app.') +param registries array = [] + +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType + +@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.') +param roleAssignments roleAssignmentType + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableDefaultTelemetry bool = true + +@description('Required. List of container definitions for the Container App.') +param containers array + +@description('Optional. List of specialized containers that run before app containers.') +param initContainersTemplate array = [] + +@description('Optional. Required if TriggerType is Event. Configuration of an event driven job.') +param eventTriggerConfig object = {} + +@description('Optional. Required if TriggerType is Schedule. Configuration of a schedule based job.') +param scheduleTriggerConfig object = {} + +@description('Optional. Required if TriggerType is Manual. Configuration of a manual job.') +param manualTriggerConfig object = {} + +@description('Optional. The maximum number of times a replica can be retried.') +param replicaRetryLimit int = 0 + +@description('Optional. The name of the workload profile to use.') +param workloadProfileName string = 'Consumption' + +@description('Optional. The secrets of the Container App.') +@secure() +param secrets object = {} + +@description('Optional. List of volume definitions for the Container App.') +param volumes array = [] + +@description('Optional. Maximum number of seconds a replica is allowed to run.') +param replicaTimeout int = 1800 + +@allowed([ + 'Event' + 'Manual' + 'Schedule' +]) +@description('Optional. Trigger type of the job.') +param triggerType string + +var secretList = !empty(secrets) ? secrets.secureList : [] + +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 = { + 'ContainerApp Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b') + 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 defaultTelemetry 'Microsoft.Resources/deployments@2021-04-01' = if (enableDefaultTelemetry) { + name: 'pid-47ed15a6-730a-4827-bcb4-0fd963ffbd82-${uniqueString(deployment().name, location)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } +} + +resource containerAppJob 'Microsoft.App/jobs@2023-05-01' = { + name: name + tags: tags + location: location + identity: identity + properties: { + environmentId: environmentId + configuration: { + eventTriggerConfig: triggerType == 'Event' ? eventTriggerConfig : null + manualTriggerConfig: triggerType == 'Manual' ? manualTriggerConfig : null + scheduleTriggerConfig: triggerType == 'Schedule' ? scheduleTriggerConfig : null + replicaRetryLimit: replicaRetryLimit + replicaTimeout: replicaTimeout + registries: !empty(registries) ? registries : null + secrets: secretList + triggerType: triggerType + } + template: { + containers: containers + initContainers: !empty(initContainersTemplate) ? initContainersTemplate : null + volumes: !empty(volumes) ? volumes : null + } + workloadProfileName: workloadProfileName + } +} + +resource containerAppJob_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: containerAppJob +} + +resource containerAppJob_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { + name: guid(containerAppJob.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: containerAppJob +}] + +@description('The resource ID of the Container App Job.') +output resourceId string = containerAppJob.id + +@description('The name of the resource group the Container App Job was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the Container App Job.') +output name string = containerAppJob.name + +@description('The location the resource was deployed into.') +output location string = containerAppJob.location + +@description('The principal ID of the system assigned identity.') +output systemAssignedPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(containerAppJob.identity, 'principalId') ? containerAppJob.identity.principalId : '' + +// =============== // +// 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' | null)? + + @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 managedIdentitiesType = { + @description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? + + @description('Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption.') + userAssignedResourcesIds: string[]? +}? diff --git a/modules/app/job/main.json b/modules/app/job/main.json new file mode 100644 index 0000000000..fa8d8beed1 --- /dev/null +++ b/modules/app/job/main.json @@ -0,0 +1,400 @@ +{ + "$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.22.6.54827", + "templateHash": "3431886018605625039" + }, + "name": "Container App Jobs", + "description": "This module deploys a Container App Job.", + "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 + }, + "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. Required if a user assigned identity is used for encryption." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "environmentId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "registries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "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." + } + }, + "enableDefaultTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Required. List of container definitions for the Container App." + } + }, + "initContainersTemplate": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of specialized containers that run before app containers." + } + }, + "eventTriggerConfig": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Required if TriggerType is Event. Configuration of an event driven job." + } + }, + "scheduleTriggerConfig": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Required if TriggerType is Schedule. Configuration of a schedule based job." + } + }, + "manualTriggerConfig": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Required if TriggerType is Manual. Configuration of a manual job." + } + }, + "replicaRetryLimit": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The maximum number of times a replica can be retried." + } + }, + "workloadProfileName": { + "type": "string", + "defaultValue": "Consumption", + "metadata": { + "description": "Optional. The name of the workload profile to use." + } + }, + "secrets": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "volumes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of volume definitions for the Container App." + } + }, + "replicaTimeout": { + "type": "int", + "defaultValue": 1800, + "metadata": { + "description": "Optional. Maximum number of seconds a replica is allowed to run." + } + }, + "triggerType": { + "type": "string", + "allowedValues": [ + "Event", + "Manual", + "Schedule" + ], + "metadata": { + "description": "Optional. Trigger type of the job." + } + } + }, + "variables": { + "secretList": "[if(not(empty(parameters('secrets'))), parameters('secrets').secureList, createArray())]", + "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": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "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": { + "defaultTelemetry": { + "condition": "[parameters('enableDefaultTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2021-04-01", + "name": "[format('pid-47ed15a6-730a-4827-bcb4-0fd963ffbd82-{0}', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] + } + } + }, + "containerAppJob": { + "type": "Microsoft.App/jobs", + "apiVersion": "2023-05-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentId')]", + "configuration": { + "eventTriggerConfig": "[if(equals(parameters('triggerType'), 'Event'), parameters('eventTriggerConfig'), null())]", + "manualTriggerConfig": "[if(equals(parameters('triggerType'), 'Manual'), parameters('manualTriggerConfig'), null())]", + "scheduleTriggerConfig": "[if(equals(parameters('triggerType'), 'Schedule'), parameters('scheduleTriggerConfig'), null())]", + "replicaRetryLimit": "[parameters('replicaRetryLimit')]", + "replicaTimeout": "[parameters('replicaTimeout')]", + "registries": "[if(not(empty(parameters('registries'))), parameters('registries'), null())]", + "secrets": "[variables('secretList')]", + "triggerType": "[parameters('triggerType')]" + }, + "template": { + "containers": "[parameters('containers')]", + "initContainers": "[if(not(empty(parameters('initContainersTemplate'))), parameters('initContainersTemplate'), null())]", + "volumes": "[if(not(empty(parameters('volumes'))), parameters('volumes'), null())]" + }, + "workloadProfileName": "[parameters('workloadProfileName')]" + } + }, + "containerAppJob_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.App/jobs/{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": [ + "containerAppJob" + ] + }, + "containerAppJob_roleAssignments": { + "copy": { + "name": "containerAppJob_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.App/jobs/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.App/jobs', 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": [ + "containerAppJob" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App Job." + }, + "value": "[resourceId('Microsoft.App/jobs', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App Job was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App Job." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerAppJob', '2023-05-01', 'full').location]" + }, + "systemAssignedPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('containerAppJob', '2023-05-01', 'full').identity, 'principalId')), reference('containerAppJob', '2023-05-01', 'full').identity.principalId, '')]" + } + } +} \ No newline at end of file diff --git a/modules/app/job/version.json b/modules/app/job/version.json new file mode 100644 index 0000000000..7fa401bdf7 --- /dev/null +++ b/modules/app/job/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From 9b099b8a497d0a4fd6acb7552a861c600f685802 Mon Sep 17 00:00:00 2001 From: CARMLPipelinePrincipal Date: Mon, 30 Oct 2023 12:07:45 +0000 Subject: [PATCH 3/7] Push updated Readme file(s) --- README.md | 1 + docs/wiki/The library - Module overview.md | 265 +++++++++++---------- 2 files changed, 134 insertions(+), 132 deletions(-) diff --git a/README.md b/README.md index b23a99af1d..2508382277 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ The CI environment supports both ARM and Bicep and can be leveraged using GitHub | `Microsoft.AnalysisServices` | [servers](https://github.com/Azure/ResourceModules/tree/main/modules/analysis-services/server) | [Analysis Services Servers](https://github.com/Azure/ResourceModules/tree/main/modules/analysis-services/server) | [![Deploy to Azure](/docs/media/deploytoazure.svg?sanitize=true)]() | | `Microsoft.ApiManagement` | [service](https://github.com/Azure/ResourceModules/tree/main/modules/api-management/service) | [API Management Services](https://github.com/Azure/ResourceModules/tree/main/modules/api-management/service) | [![Deploy to Azure](/docs/media/deploytoazure.svg?sanitize=true)]() | | `Microsoft.App` | [containerApps](https://github.com/Azure/ResourceModules/tree/main/modules/app/container-app) | [Container Apps](https://github.com/Azure/ResourceModules/tree/main/modules/app/container-app) | [![Deploy to Azure](/docs/media/deploytoazure.svg?sanitize=true)]() | +| | [jobs](https://github.com/Azure/ResourceModules/tree/main/modules/app/job) | [Container App Jobs](https://github.com/Azure/ResourceModules/tree/main/modules/app/job) | [![Deploy to Azure](/docs/media/deploytoazure.svg?sanitize=true)]() | | | [managedEnvironments](https://github.com/Azure/ResourceModules/tree/main/modules/app/managed-environment) | [App ManagedEnvironments](https://github.com/Azure/ResourceModules/tree/main/modules/app/managed-environment) | [![Deploy to Azure](/docs/media/deploytoazure.svg?sanitize=true)]() | | `Microsoft.AppConfiguration` | [configurationStores](https://github.com/Azure/ResourceModules/tree/main/modules/app-configuration/configuration-store) | [App Configuration Stores](https://github.com/Azure/ResourceModules/tree/main/modules/app-configuration/configuration-store) | [![Deploy to Azure](/docs/media/deploytoazure.svg?sanitize=true)]() | | `Microsoft.Authorization` | [locks](https://github.com/Azure/ResourceModules/tree/main/modules/authorization/lock) | [Authorization Locks (All scopes)](https://github.com/Azure/ResourceModules/tree/main/modules/authorization/lock) | [![Deploy to Azure](/docs/media/deploytoazure.svg?sanitize=true)]() | diff --git a/docs/wiki/The library - Module overview.md b/docs/wiki/The library - Module overview.md index 0b3fa0a934..a25d8ce89f 100644 --- a/docs/wiki/The library - Module overview.md +++ b/docs/wiki/The library - Module overview.md @@ -18,138 +18,139 @@ This section provides an overview of the library's feature set. | 3 | api-management

service | [![ApiManagement - Service](https://github.com/Azure/ResourceModules/workflows/ApiManagement%20-%20Service/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.apimanagement.service.yml) | | | :white_check_mark: | | | | [L1:11, L2:3] | 451 | | 4 | app-configuration

configuration-store | [![AppConfiguration - ConfigurationStores](https://github.com/Azure/ResourceModules/workflows/AppConfiguration%20-%20ConfigurationStores/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.appconfiguration.configurationstores.yml) | | | :white_check_mark: | | | | [L1:1] | 305 | | 5 | app

container-app | [![App - ContainerApps](https://github.com/Azure/ResourceModules/workflows/App%20-%20ContainerApps/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.app.containerapps.yml) | | | :white_check_mark: | | | | | 205 | -| 6 | app

managed-environment | [![App - Managed Environments](https://github.com/Azure/ResourceModules/workflows/App%20-%20Managed%20Environments/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.app.managedenvironments.yml) | | | :white_check_mark: | | | | | 163 | -| 7 | authorization

lock | [![Authorization - Locks](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20Locks/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.locks.yml) | | | | | | | [L1:2] | 62 | -| 8 | authorization

policy-assignment | [![Authorization - PolicyAssignments](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20PolicyAssignments/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.policyassignments.yml) | | | | | | | [L1:3] | 143 | -| 9 | authorization

policy-definition | [![Authorization - PolicyDefinitions](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20PolicyDefinitions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.policydefinitions.yml) | | | | | | | [L1:2] | 86 | -| 10 | authorization

policy-exemption | [![Authorization - PolicyExemptions](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20PolicyExemptions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.policyexemptions.yml) | | | | | | | [L1:3] | 114 | -| 11 | authorization

policy-set-definition | [![Authorization - PolicySetDefinitions](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20PolicySetDefinitions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.policysetdefinitions.yml) | | | | | | | [L1:2] | 76 | -| 12 | authorization

role-assignment | [![Authorization - RoleAssignments](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20RoleAssignments/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.roleassignments.yml) | | | | | | | [L1:3] | 107 | -| 13 | authorization

role-definition | [![Authorization - RoleDefinitions](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20RoleDefinitions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.roledefinitions.yml) | | | | | | | [L1:3] | 94 | -| 14 | automation

automation-account | [![Automation - AutomationAccounts](https://github.com/Azure/ResourceModules/workflows/Automation%20-%20AutomationAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.automation.automationaccounts.yml) | | | :white_check_mark: | | | | [L1:6] | 437 | -| 15 | batch

batch-account | [![Batch - BatchAccounts](https://github.com/Azure/ResourceModules/workflows/Batch%20-%20BatchAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.batch.batchaccounts.yml) | | | :white_check_mark: | | | | | 311 | -| 16 | cache

redis | [![Cache - Redis](https://github.com/Azure/ResourceModules/workflows/Cache%20-%20Redis/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.cache.redis.yml) | | | :white_check_mark: | | | | | 312 | -| 17 | cache

redis-enterprise | [![Cache - Redis Enterprise](https://github.com/Azure/ResourceModules/workflows/Cache%20-%20Redis%20Enterprise/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.cache.redisenterprise.yml) | | | :white_check_mark: | | | | [L1:1] | 268 | -| 18 | cdn

profile | [![CDN - Profiles](https://github.com/Azure/ResourceModules/workflows/CDN%20-%20Profiles/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.cdn.profiles.yml) | | | :white_check_mark: | | | | [L1:6, L2:4] | 220 | -| 19 | cognitive-services

account | [![CognitiveServices - Accounts](https://github.com/Azure/ResourceModules/workflows/CognitiveServices%20-%20Accounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.cognitiveservices.accounts.yml) | | | :white_check_mark: | | | | | 375 | -| 20 | compute

availability-set | [![Compute - AvailabilitySets](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20AvailabilitySets/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.availabilitysets.yml) | | | :white_check_mark: | | | | | 111 | -| 21 | compute

disk | [![Compute - Disks](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20Disks/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.disks.yml) | | | :white_check_mark: | | | | | 218 | -| 22 | compute

disk-encryption-set | [![Compute - DiskEncryptionSets](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20DiskEncryptionSets/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.diskencryptionsets.yml) | | | :white_check_mark: | | | | [L1:1] | 162 | -| 23 | compute

gallery | [![Compute - Galleries](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20Galleries/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.galleries.yml) | | | :white_check_mark: | | | | [L1:2] | 155 | -| 24 | compute

image | [![Compute - Images](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20Images/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.images.yml) | | | :white_check_mark: | | | | | 137 | -| 25 | compute

proximity-placement-group | [![Compute - ProximityPlacementGroups](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20ProximityPlacementGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.proximityplacementgroups.yml) | | | :white_check_mark: | | | | | 111 | -| 26 | compute

ssh-public-key | [![Compute - SshPublicKeys](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20SshPublicKeys/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.sshpublickeys.yml) | | | :white_check_mark: | | | | | 99 | -| 27 | compute

virtual-machine | [![Compute - VirtualMachines](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20VirtualMachines/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.virtualmachines.yml) | | | :white_check_mark: | | | | [L1:2] | 663 | -| 28 | compute

virtual-machine-scale-set | [![Compute - VirtualMachineScaleSets](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20VirtualMachineScaleSets/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.virtualmachinescalesets.yml) | | | :white_check_mark: | | | | [L1:1] | 607 | -| 29 | consumption

budget | [![Consumption - Budgets](https://github.com/Azure/ResourceModules/workflows/Consumption%20-%20Budgets/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.consumption.budgets.yml) | | | | | | | | 92 | -| 30 | container-instance

container-group | [![ContainerInstance - ContainerGroups](https://github.com/Azure/ResourceModules/workflows/ContainerInstance%20-%20ContainerGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.containerinstance.containergroups.yml) | | | :white_check_mark: | | | | | 163 | -| 31 | container-registry

registry | [![ContainerRegistry - Registries](https://github.com/Azure/ResourceModules/workflows/ContainerRegistry%20-%20Registries/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.containerregistry.registries.yml) | | | :white_check_mark: | | | | [L1:3] | 430 | -| 32 | container-service

managed-cluster | [![ContainerService - ManagedClusters](https://github.com/Azure/ResourceModules/workflows/ContainerService%20-%20ManagedClusters/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.containerservice.managedclusters.yml) | | | :white_check_mark: | | | | [L1:1] | 664 | -| 33 | data-factory

factory | [![DataFactory - Factories](https://github.com/Azure/ResourceModules/workflows/DataFactory%20-%20Factories/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.datafactory.factories.yml) | | | :white_check_mark: | | | | [L1:2, L2:1] | 318 | -| 34 | data-protection

backup-vault | [![DataProtection - BackupVaults](https://github.com/Azure/ResourceModules/workflows/DataProtection%20-%20BackupVaults/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.dataprotection.backupvaults.yml) | | | :white_check_mark: | | | | [L1:1] | 156 | -| 35 | databricks

access-connector | [![Databricks - Access Connectors](https://github.com/Azure/ResourceModules/workflows/Databricks%20-%20Access%20Connectors/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.databricks.accessconnectors.yml) | | | :white_check_mark: | | | | | 104 | -| 36 | databricks

workspace | [![Databricks - Workspaces](https://github.com/Azure/ResourceModules/workflows/Databricks%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.databricks.workspaces.yml) | | | :white_check_mark: | | | | | 376 | -| 37 | db-for-my-sql

flexible-server | [![DbForMySQL - FlexibleServers](https://github.com/Azure/ResourceModules/workflows/DbForMySQL%20-%20FlexibleServers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.dbformysql.flexibleservers.yml) | | | :white_check_mark: | | | | [L1:3] | 370 | -| 38 | db-for-postgre-sql

flexible-server | [![DbForPostgreSQL - FlexibleServers](https://github.com/Azure/ResourceModules/workflows/DbForPostgreSQL%20-%20FlexibleServers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.dbforpostgresql.flexibleservers.yml) | | | :white_check_mark: | | | | [L1:4] | 364 | -| 39 | desktop-virtualization

application-group | [![DesktopVirtualization - ApplicationGroups](https://github.com/Azure/ResourceModules/workflows/DesktopVirtualization%20-%20ApplicationGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.desktopvirtualization.applicationgroups.yml) | | | :white_check_mark: | | | | [L1:1] | 191 | -| 40 | desktop-virtualization

host-pool | [![DesktopVirtualization - HostPools](https://github.com/Azure/ResourceModules/workflows/DesktopVirtualization%20-%20HostPools/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.desktopvirtualization.hostpools.yml) | | | :white_check_mark: | | | | | 281 | -| 41 | desktop-virtualization

scaling-plan | [![DesktopVirtualization - Scalingplans](https://github.com/Azure/ResourceModules/workflows/DesktopVirtualization%20-%20Scalingplans/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.desktopvirtualization.scalingplans.yml) | | | :white_check_mark: | | | | | 200 | -| 42 | desktop-virtualization

workspace | [![DesktopVirtualization - Workspaces](https://github.com/Azure/ResourceModules/workflows/DesktopVirtualization%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.desktopvirtualization.workspaces.yml) | | | :white_check_mark: | | | | | 161 | -| 43 | dev-test-lab

lab | [![DevTestLab - Labs](https://github.com/Azure/ResourceModules/workflows/DevTestLab%20-%20Labs/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.devtestlab.labs.yml) | | | :white_check_mark: | | | | [L1:6, L2:1] | 295 | -| 44 | digital-twins

digital-twins-instance | [![DigitalTwins - DigitalTwinsInstances](https://github.com/Azure/ResourceModules/workflows/DigitalTwins%20-%20DigitalTwinsInstances/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.digitaltwins.digitaltwinsinstances.yml) | | | :white_check_mark: | | | | [L1:3] | 292 | -| 45 | document-db

database-account | [![DocumentDB - DatabaseAccounts](https://github.com/Azure/ResourceModules/workflows/DocumentDB%20-%20DatabaseAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.documentdb.databaseaccounts.yml) | | | :white_check_mark: | | | | [L1:3, L2:3] | 400 | -| 46 | event-grid

domain | [![EventGrid - Domains](https://github.com/Azure/ResourceModules/workflows/EventGrid%20-%20Domains/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.eventgrid.domains.yml) | | | :white_check_mark: | | | | [L1:1] | 248 | -| 47 | event-grid

system-topic | [![EventGrid - System Topics](https://github.com/Azure/ResourceModules/workflows/EventGrid%20-%20System%20Topics/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.eventgrid.systemtopics.yml) | | | :white_check_mark: | | | | [L1:1] | 193 | -| 48 | event-grid

topic | [![EventGrid - Topics](https://github.com/Azure/ResourceModules/workflows/EventGrid%20-%20Topics/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.eventgrid.topics.yml) | | | :white_check_mark: | | | | [L1:1] | 252 | -| 49 | event-hub

namespace | [![EventHub - Namespaces](https://github.com/Azure/ResourceModules/workflows/EventHub%20-%20Namespaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.eventhub.namespaces.yml) | | | :white_check_mark: | | | | [L1:4, L2:2] | 397 | -| 50 | health-bot

health-bot | [![HealthBot - HealthBots](https://github.com/Azure/ResourceModules/workflows/HealthBot%20-%20HealthBots/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.healthbot.healthbots.yml) | | | :white_check_mark: | | | | | 112 | -| 51 | healthcare-apis

workspace | [![HealthcareApis - Workspaces](https://github.com/Azure/ResourceModules/workflows/HealthcareApis%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.healthcareapis.workspaces.yml) | | | :white_check_mark: | | | | [L1:3, L2:1] | 198 | -| 52 | insights

action-group | [![Insights - ActionGroups](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20ActionGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.actiongroups.yml) | | | :white_check_mark: | | | | | 115 | -| 53 | insights

activity-log-alert | [![Insights - ActivityLogAlerts](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20ActivityLogAlerts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.activitylogalerts.yml) | | | :white_check_mark: | | | | | 104 | -| 54 | insights

component | [![Insights - Components](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20Components/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.components.yml) | | | :white_check_mark: | | | | | 184 | -| 55 | insights

data-collection-endpoint | [![Insights - DataCollectionEndpoints](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20DataCollectionEndpoints/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.datacollectionendpoints.yml) | | | :white_check_mark: | | | | | 120 | -| 56 | insights

data-collection-rule | [![Insights - DataCollectionRules](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20DataCollectionRules/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.datacollectionrules.yml) | | | :white_check_mark: | | | | | 129 | -| 57 | insights

diagnostic-setting | [![Insights - DiagnosticSettings](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20DiagnosticSettings/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.diagnosticsettings.yml) | | | | | | | | 91 | -| 58 | insights

metric-alert | [![Insights - MetricAlerts](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20MetricAlerts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.metricalerts.yml) | | | :white_check_mark: | | | | | 152 | -| 59 | insights

private-link-scope | [![Insights - PrivateLinkScopes](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20PrivateLinkScopes/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.privatelinkscopes.yml) | | | :white_check_mark: | | | | [L1:1] | 172 | -| 60 | insights

scheduled-query-rule | [![Insights - ScheduledQueryRules](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20ScheduledQueryRules/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.scheduledqueryrules.yml) | | | :white_check_mark: | | | | | 136 | -| 61 | insights

webtest | [![Insights - Web Tests](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20Web%20Tests/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.webtests.yml) | | | | | | | | 152 | -| 62 | key-vault

vault | [![KeyVault - Vaults](https://github.com/Azure/ResourceModules/workflows/KeyVault%20-%20Vaults/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.keyvault.vaults.yml) | | | :white_check_mark: | | | | [L1:3] | 347 | -| 63 | kubernetes-configuration

extension | [![KubernetesConfiguration - Extensions](https://github.com/Azure/ResourceModules/workflows/KubernetesConfiguration%20-%20Extensions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.kubernetesconfiguration.extensions.yml) | | | | | | | | 88 | -| 64 | kubernetes-configuration

flux-configuration | [![KubernetesConfiguration - FluxConfigurations](https://github.com/Azure/ResourceModules/workflows/KubernetesConfiguration%20-%20FluxConfigurations/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.kubernetesconfiguration.fluxconfigurations.yml) | | | | | | | | 71 | -| 65 | logic

workflow | [![Logic - Workflows](https://github.com/Azure/ResourceModules/workflows/Logic%20-%20Workflows/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.logic.workflows.yml) | | | :white_check_mark: | | | | | 227 | -| 66 | machine-learning-services

workspace | [![MachineLearningServices - Workspaces](https://github.com/Azure/ResourceModules/workflows/MachineLearningServices%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.machinelearningservices.workspaces.yml) | | | :white_check_mark: | | | | [L1:1] | 352 | -| 67 | maintenance

maintenance-configuration | [![Maintenance - MaintenanceConfigurations](https://github.com/Azure/ResourceModules/workflows/Maintenance%20-%20MaintenanceConfigurations/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.maintenance.maintenanceconfigurations.yml) | | | :white_check_mark: | | | | | 136 | -| 68 | managed-identity

user-assigned-identity | [![ManagedIdentity - UserAssignedIdentities](https://github.com/Azure/ResourceModules/workflows/ManagedIdentity%20-%20UserAssignedIdentities/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.managedidentity.userassignedidentities.yml) | | | :white_check_mark: | | | | [L1:1] | 113 | -| 69 | managed-services

registration-definition | [![ManagedServices - RegistrationDefinitions](https://github.com/Azure/ResourceModules/workflows/ManagedServices%20-%20RegistrationDefinitions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.managedservices.registrationdefinitions.yml) | | | | | | | | 67 | -| 70 | management

management-group | [![Management - ManagementGroups](https://github.com/Azure/ResourceModules/workflows/Management%20-%20ManagementGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.management.managementgroups.yml) | | | | | | | | 50 | -| 71 | net-app

net-app-account | [![NetApp - NetAppAccounts](https://github.com/Azure/ResourceModules/workflows/NetApp%20-%20NetAppAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.netapp.netappaccounts.yml) | | | :white_check_mark: | | | | [L1:1, L2:1] | 147 | -| 72 | network

application-gateway | [![Network - ApplicationGateways](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ApplicationGateways/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.applicationgateways.yml) | | | :white_check_mark: | | | | | 416 | -| 73 | network

application-gateway-web-application-firewall-policy | [![Network - ApplicationGatewayWebApplicationFirewallPolicies](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ApplicationGatewayWebApplicationFirewallPolicies/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.applicationgatewaywebapplicationfirewallpolicies.yml) | | | :white_check_mark: | | | | | 47 | -| 74 | network

application-security-group | [![Network - ApplicationSecurityGroups](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ApplicationSecurityGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.applicationsecuritygroups.yml) | | | :white_check_mark: | | | | | 94 | -| 75 | network

azure-firewall | [![Network - AzureFirewalls](https://github.com/Azure/ResourceModules/workflows/Network%20-%20AzureFirewalls/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.azurefirewalls.yml) | | | :white_check_mark: | | | :white_check_mark: | | 335 | -| 76 | network

bastion-host | [![Network - BastionHosts](https://github.com/Azure/ResourceModules/workflows/Network%20-%20BastionHosts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.bastionhosts.yml) | | | :white_check_mark: | | | :white_check_mark: | | 268 | -| 77 | network

connection | [![Network - Connections](https://github.com/Azure/ResourceModules/workflows/Network%20-%20Connections/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.connections.yml) | | | :white_check_mark: | | | | | 147 | -| 78 | network

ddos-protection-plan | [![Network - DdosProtectionPlans](https://github.com/Azure/ResourceModules/workflows/Network%20-%20DdosProtectionPlans/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.ddosprotectionplans.yml) | | | :white_check_mark: | | | | | 95 | -| 79 | network

dns-forwarding-ruleset | [![Network - DNS Forwarding Rulesets](https://github.com/Azure/ResourceModules/workflows/Network%20-%20DNS%20Forwarding%20Rulesets/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.dnsforwardingrulesets.yml) | | | :white_check_mark: | | | | [L1:2] | 126 | -| 80 | network

dns-resolver | [![Network - DNS Resolvers](https://github.com/Azure/ResourceModules/workflows/Network%20-%20DNS%20Resolvers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.dnsresolvers.yml) | | | :white_check_mark: | | | | | 137 | -| 81 | network

dns-zone | [![Network - Public DnsZones](https://github.com/Azure/ResourceModules/workflows/Network%20-%20Public%20DnsZones/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.dnszones.yml) | | | :white_check_mark: | | | | [L1:10] | 248 | -| 82 | network

express-route-circuit | [![Network - ExpressRouteCircuits](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ExpressRouteCircuits/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.expressroutecircuits.yml) | | | :white_check_mark: | | | | | 228 | -| 83 | network

express-route-gateway | [![Network - ExpressRouteGateways](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ExpressRouteGateways/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.expressroutegateways.yml) | | | :white_check_mark: | | | | | 117 | -| 84 | network

firewall-policy | [![Network - FirewallPolicies](https://github.com/Azure/ResourceModules/workflows/Network%20-%20FirewallPolicies/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.firewallpolicies.yml) | | | :white_check_mark: | | | | [L1:1] | 166 | -| 85 | network

front-door | [![Network - Frontdoors](https://github.com/Azure/ResourceModules/workflows/Network%20-%20Frontdoors/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.frontdoors.yml) | | | :white_check_mark: | | | | | 181 | -| 86 | network

front-door-web-application-firewall-policy | [![Network - FrontDoorWebApplicationFirewallPolicies](https://github.com/Azure/ResourceModules/workflows/Network%20-%20FrontDoorWebApplicationFirewallPolicies/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.frontdoorwebapplicationfirewallpolicies.yml) | | | :white_check_mark: | | | | | 152 | -| 87 | network

ip-group | [![Network - IpGroups](https://github.com/Azure/ResourceModules/workflows/Network%20-%20IpGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.ipgroups.yml) | | | :white_check_mark: | | | | | 100 | -| 88 | network

load-balancer | [![Network - LoadBalancers](https://github.com/Azure/ResourceModules/workflows/Network%20-%20LoadBalancers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.loadbalancers.yml) | | | :white_check_mark: | | | | [L1:2] | 272 | -| 89 | network

local-network-gateway | [![Network - LocalNetworkGateways](https://github.com/Azure/ResourceModules/workflows/Network%20-%20LocalNetworkGateways/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.localnetworkgateways.yml) | | | :white_check_mark: | | | | | 120 | -| 90 | network

nat-gateway | [![Network - NatGateways](https://github.com/Azure/ResourceModules/workflows/Network%20-%20NatGateways/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.natgateways.yml) | | | :white_check_mark: | | | | | 181 | -| 91 | network

network-interface | [![Network - NetworkInterfaces](https://github.com/Azure/ResourceModules/workflows/Network%20-%20NetworkInterfaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.networkinterfaces.yml) | | | :white_check_mark: | | | | | 198 | -| 92 | network

network-manager | [![Network - Network Managers](https://github.com/Azure/ResourceModules/workflows/Network%20-%20Network%20Managers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.networkmanagers.yml) | | | :white_check_mark: | | | | [L1:4, L2:2, L3:1] | 165 | -| 93 | network

network-security-group | [![Network - NetworkSecurityGroups](https://github.com/Azure/ResourceModules/workflows/Network%20-%20NetworkSecurityGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.networksecuritygroups.yml) | | | :white_check_mark: | | | | [L1:1] | 188 | -| 94 | network

network-watcher | [![Network - NetworkWatchers](https://github.com/Azure/ResourceModules/workflows/Network%20-%20NetworkWatchers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.networkwatchers.yml) | | | :white_check_mark: | | | | [L1:2] | 129 | -| 95 | network

private-dns-zone | [![Network - PrivateDnsZones](https://github.com/Azure/ResourceModules/workflows/Network%20-%20PrivateDnsZones/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.privatednszones.yml) | | | :white_check_mark: | | | | [L1:9] | 226 | -| 96 | network

private-endpoint | [![Network - PrivateEndpoints](https://github.com/Azure/ResourceModules/workflows/Network%20-%20PrivateEndpoints/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.privateendpoints.yml) | | | | | | | [L1:1] | 149 | -| 97 | network

private-link-service | [![Network - PrivateLinkServices](https://github.com/Azure/ResourceModules/workflows/Network%20-%20PrivateLinkServices/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.privatelinkservices.yml) | | | :white_check_mark: | | | | | 121 | -| 98 | network

public-ip-address | [![Network - PublicIpAddresses](https://github.com/Azure/ResourceModules/workflows/Network%20-%20PublicIpAddresses/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.publicipaddresses.yml) | | | :white_check_mark: | | | | | 214 | -| 99 | network

public-ip-prefix | [![Network - PublicIpPrefixes](https://github.com/Azure/ResourceModules/workflows/Network%20-%20PublicIpPrefixes/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.publicipprefixes.yml) | | | :white_check_mark: | | | | | 109 | -| 100 | network

route-table | [![Network - RouteTables](https://github.com/Azure/ResourceModules/workflows/Network%20-%20RouteTables/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.routetables.yml) | | | :white_check_mark: | | | | | 102 | -| 101 | network

service-endpoint-policy | [![Network - ServiceEndpointPolicies](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ServiceEndpointPolicies/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.serviceendpointpolicies.yml) | | | :white_check_mark: | | | | | 105 | -| 102 | network

trafficmanagerprofile | [![Network - TrafficManagerProfiles](https://github.com/Azure/ResourceModules/workflows/Network%20-%20TrafficManagerProfiles/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.trafficmanagerprofiles.yml) | | | :white_check_mark: | | | | | 195 | -| 103 | network

virtual-hub | [![Network - VirtualHubs](https://github.com/Azure/ResourceModules/workflows/Network%20-%20VirtualHubs/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.virtualhubs.yml) | | | :white_check_mark: | | | | [L1:2] | 151 | -| 104 | network

virtual-network | [![Network - VirtualNetworks](https://github.com/Azure/ResourceModules/workflows/Network%20-%20VirtualNetworks/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.virtualnetworks.yml) | | | :white_check_mark: | | | | [L1:2] | 276 | -| 105 | network

virtual-network-gateway | [![Network - VirtualNetworkGateways](https://github.com/Azure/ResourceModules/workflows/Network%20-%20VirtualNetworkGateways/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.virtualnetworkgateways.yml) | | | :white_check_mark: | | | | [L1:1] | 403 | -| 106 | network

virtual-wan | [![Network - VirtualWans](https://github.com/Azure/ResourceModules/workflows/Network%20-%20VirtualWans/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.virtualwans.yml) | | | :white_check_mark: | | | | | 112 | -| 107 | network

vpn-gateway | [![Network - VPNGateways](https://github.com/Azure/ResourceModules/workflows/Network%20-%20VPNGateways/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.vpngateways.yml) | | | :white_check_mark: | | | | [L1:2] | 114 | -| 108 | network

vpn-site | [![Network - VPN Sites](https://github.com/Azure/ResourceModules/workflows/Network%20-%20VPN%20Sites/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.vpnsites.yml) | | | :white_check_mark: | | | | | 124 | -| 109 | operational-insights

workspace | [![OperationalInsights - Workspaces](https://github.com/Azure/ResourceModules/workflows/OperationalInsights%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.operationalinsights.workspaces.yml) | | | :white_check_mark: | | | | [L1:7] | 344 | -| 110 | operations-management

solution | [![OperationsManagement - Solutions](https://github.com/Azure/ResourceModules/workflows/OperationsManagement%20-%20Solutions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.operationsmanagement.solutions.yml) | | | | | | | | 53 | -| 111 | policy-insights

remediation | [![PolicyInsights - Remediations](https://github.com/Azure/ResourceModules/workflows/PolicyInsights%20-%20Remediations/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.policyinsights.remediations.yml) | | | | | | | [L1:3] | 106 | -| 112 | power-bi-dedicated

capacity | [![PowerBiDedicated - Capacities](https://github.com/Azure/ResourceModules/workflows/PowerBiDedicated%20-%20Capacities/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.powerbidedicated.capacities.yml) | | | :white_check_mark: | | | | | 133 | -| 113 | purview

account | [![Purview - Accounts](https://github.com/Azure/ResourceModules/workflows/Purview%20-%20Accounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.purview.accounts.yml) | | | :white_check_mark: | | | | | 311 | -| 114 | recovery-services

vault | [![RecoveryServices - Vaults](https://github.com/Azure/ResourceModules/workflows/RecoveryServices%20-%20Vaults/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.recoveryservices.vaults.yml) | | | :white_check_mark: | | | | [L1:7, L2:2, L3:2] | 351 | -| 115 | relay

namespace | [![Relay - Namespaces](https://github.com/Azure/ResourceModules/workflows/Relay%20-%20Namespaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.relay.namespaces.yml) | | | :white_check_mark: | | | | [L1:4, L2:2] | 330 | -| 116 | resource-graph

query | [![ResourceGraph - Queries](https://github.com/Azure/ResourceModules/workflows/ResourceGraph%20-%20Queries/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.resourcegraph.queries.yml) | | | :white_check_mark: | | | | | 101 | -| 117 | resources

deployment-script | [![Resources - DeploymentScripts](https://github.com/Azure/ResourceModules/workflows/Resources%20-%20DeploymentScripts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.resources.deploymentscripts.yml) | | | :white_check_mark: | | | | | 128 | -| 118 | resources

resource-group | [![Resources - ResourceGroups](https://github.com/Azure/ResourceModules/workflows/Resources%20-%20ResourceGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.resources.resourcegroups.yml) | | | :white_check_mark: | | | | [L1:1] | 101 | -| 119 | resources

tags | [![Resources - Tags](https://github.com/Azure/ResourceModules/workflows/Resources%20-%20Tags/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.resources.tags.yml) | | | :white_check_mark: | | | | [L1:2] | 54 | -| 120 | search

search-service | [![Search - SearchServices](https://github.com/Azure/ResourceModules/workflows/Search%20-%20SearchServices/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.search.searchservices.yml) | | | :white_check_mark: | | | | [L1:1] | 313 | -| 121 | security

azure-security-center | [![Security - AzureSecurityCenter](https://github.com/Azure/ResourceModules/workflows/Security%20-%20AzureSecurityCenter/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.security.azuresecuritycenter.yml) | | | | | | | | 221 | -| 122 | service-bus

namespace | [![ServiceBus - Namespaces](https://github.com/Azure/ResourceModules/workflows/ServiceBus%20-%20Namespaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.servicebus.namespaces.yml) | | | :white_check_mark: | | | | [L1:6, L2:2] | 441 | -| 123 | service-fabric

cluster | [![ServiceFabric - Clusters](https://github.com/Azure/ResourceModules/workflows/ServiceFabric%20-%20Clusters/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.servicefabric.clusters.yml) | | | :white_check_mark: | | | | [L1:1] | 312 | -| 124 | signal-r-service

signal-r | [![SignalRService - SignalR](https://github.com/Azure/ResourceModules/workflows/SignalRService%20-%20SignalR/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.signalrservice.signalr.yml) | | | :white_check_mark: | | | | | 268 | -| 125 | signal-r-service

web-pub-sub | [![SignalRService - WebPubSub](https://github.com/Azure/ResourceModules/workflows/SignalRService%20-%20WebPubSub/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.signalrservice.webpubsub.yml) | | | :white_check_mark: | | | | | 238 | -| 126 | sql

managed-instance | [![Sql - ManagedInstances](https://github.com/Azure/ResourceModules/workflows/Sql%20-%20ManagedInstances/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.sql.managedinstances.yml) | | | :white_check_mark: | | | | [L1:6, L2:3] | 369 | -| 127 | sql

server | [![Sql - Servers](https://github.com/Azure/ResourceModules/workflows/Sql%20-%20Servers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.sql.servers.yml) | | | :white_check_mark: | | | | [L1:8, L2:3] | 376 | -| 128 | storage

storage-account | [![Storage - StorageAccounts](https://github.com/Azure/ResourceModules/workflows/Storage%20-%20StorageAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.storage.storageaccounts.yml) | | | :white_check_mark: | | | | [L1:6, L2:4, L3:1] | 500 | -| 129 | synapse

private-link-hub | [![Synapse - PrivateLinkHubs](https://github.com/Azure/ResourceModules/workflows/Synapse%20-%20PrivateLinkHubs/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.synapse.privatelinkhubs.yml) | | | :white_check_mark: | | | | | 162 | -| 130 | synapse

workspace | [![Synapse - Workspaces](https://github.com/Azure/ResourceModules/workflows/Synapse%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.synapse.workspaces.yml) | | | :white_check_mark: | | | | [L1:3] | 355 | -| 131 | virtual-machine-images

image-template | [![VirtualMachineImages - ImageTemplates](https://github.com/Azure/ResourceModules/workflows/VirtualMachineImages%20-%20ImageTemplates/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.virtualmachineimages.imagetemplates.yml) | | | :white_check_mark: | | | | | 216 | -| 132 | web

connection | [![Web - Connections](https://github.com/Azure/ResourceModules/workflows/Web%20-%20Connections/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.connections.yml) | | | :white_check_mark: | | | | | 118 | -| 133 | web

hosting-environment | [![Web - HostingEnvironments](https://github.com/Azure/ResourceModules/workflows/Web%20-%20HostingEnvironments/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.hostingenvironments.yml) | | | :white_check_mark: | | | | [L1:2] | 258 | -| 134 | web

serverfarm | [![Web - Serverfarms](https://github.com/Azure/ResourceModules/workflows/Web%20-%20Serverfarms/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.serverfarms.yml) | | | :white_check_mark: | | | | | 194 | -| 135 | web

site | [![Web - Sites](https://github.com/Azure/ResourceModules/workflows/Web%20-%20Sites/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.sites.yml) | | | :white_check_mark: | | | | [L1:5, L2:4, L3:1] | 441 | -| 136 | web

static-site | [![Web - StaticSites](https://github.com/Azure/ResourceModules/workflows/Web%20-%20StaticSites/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.staticsites.yml) | | | :white_check_mark: | | | | [L1:3] | 271 | -| Sum | | | 0 | 0 | 118 | 0 | 0 | 2 | 240 | 29199 | +| 6 | app

job | [![App - Jobs](https://github.com/Azure/ResourceModules/workflows/App%20-%20Jobs/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.app.jobs.yml) | | | :white_check_mark: | | | | | 162 | +| 7 | app

managed-environment | [![App - Managed Environments](https://github.com/Azure/ResourceModules/workflows/App%20-%20Managed%20Environments/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.app.managedenvironments.yml) | | | :white_check_mark: | | | | | 163 | +| 8 | authorization

lock | [![Authorization - Locks](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20Locks/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.locks.yml) | | | | | | | [L1:2] | 62 | +| 9 | authorization

policy-assignment | [![Authorization - PolicyAssignments](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20PolicyAssignments/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.policyassignments.yml) | | | | | | | [L1:3] | 143 | +| 10 | authorization

policy-definition | [![Authorization - PolicyDefinitions](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20PolicyDefinitions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.policydefinitions.yml) | | | | | | | [L1:2] | 86 | +| 11 | authorization

policy-exemption | [![Authorization - PolicyExemptions](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20PolicyExemptions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.policyexemptions.yml) | | | | | | | [L1:3] | 114 | +| 12 | authorization

policy-set-definition | [![Authorization - PolicySetDefinitions](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20PolicySetDefinitions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.policysetdefinitions.yml) | | | | | | | [L1:2] | 76 | +| 13 | authorization

role-assignment | [![Authorization - RoleAssignments](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20RoleAssignments/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.roleassignments.yml) | | | | | | | [L1:3] | 107 | +| 14 | authorization

role-definition | [![Authorization - RoleDefinitions](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20RoleDefinitions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.roledefinitions.yml) | | | | | | | [L1:3] | 94 | +| 15 | automation

automation-account | [![Automation - AutomationAccounts](https://github.com/Azure/ResourceModules/workflows/Automation%20-%20AutomationAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.automation.automationaccounts.yml) | | | :white_check_mark: | | | | [L1:6] | 437 | +| 16 | batch

batch-account | [![Batch - BatchAccounts](https://github.com/Azure/ResourceModules/workflows/Batch%20-%20BatchAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.batch.batchaccounts.yml) | | | :white_check_mark: | | | | | 311 | +| 17 | cache

redis | [![Cache - Redis](https://github.com/Azure/ResourceModules/workflows/Cache%20-%20Redis/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.cache.redis.yml) | | | :white_check_mark: | | | | | 312 | +| 18 | cache

redis-enterprise | [![Cache - Redis Enterprise](https://github.com/Azure/ResourceModules/workflows/Cache%20-%20Redis%20Enterprise/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.cache.redisenterprise.yml) | | | :white_check_mark: | | | | [L1:1] | 268 | +| 19 | cdn

profile | [![CDN - Profiles](https://github.com/Azure/ResourceModules/workflows/CDN%20-%20Profiles/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.cdn.profiles.yml) | | | :white_check_mark: | | | | [L1:6, L2:4] | 220 | +| 20 | cognitive-services

account | [![CognitiveServices - Accounts](https://github.com/Azure/ResourceModules/workflows/CognitiveServices%20-%20Accounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.cognitiveservices.accounts.yml) | | | :white_check_mark: | | | | | 375 | +| 21 | compute

availability-set | [![Compute - AvailabilitySets](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20AvailabilitySets/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.availabilitysets.yml) | | | :white_check_mark: | | | | | 111 | +| 22 | compute

disk | [![Compute - Disks](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20Disks/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.disks.yml) | | | :white_check_mark: | | | | | 218 | +| 23 | compute

disk-encryption-set | [![Compute - DiskEncryptionSets](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20DiskEncryptionSets/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.diskencryptionsets.yml) | | | :white_check_mark: | | | | [L1:1] | 162 | +| 24 | compute

gallery | [![Compute - Galleries](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20Galleries/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.galleries.yml) | | | :white_check_mark: | | | | [L1:2] | 155 | +| 25 | compute

image | [![Compute - Images](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20Images/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.images.yml) | | | :white_check_mark: | | | | | 137 | +| 26 | compute

proximity-placement-group | [![Compute - ProximityPlacementGroups](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20ProximityPlacementGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.proximityplacementgroups.yml) | | | :white_check_mark: | | | | | 111 | +| 27 | compute

ssh-public-key | [![Compute - SshPublicKeys](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20SshPublicKeys/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.sshpublickeys.yml) | | | :white_check_mark: | | | | | 99 | +| 28 | compute

virtual-machine | [![Compute - VirtualMachines](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20VirtualMachines/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.virtualmachines.yml) | | | :white_check_mark: | | | | [L1:2] | 663 | +| 29 | compute

virtual-machine-scale-set | [![Compute - VirtualMachineScaleSets](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20VirtualMachineScaleSets/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.virtualmachinescalesets.yml) | | | :white_check_mark: | | | | [L1:1] | 607 | +| 30 | consumption

budget | [![Consumption - Budgets](https://github.com/Azure/ResourceModules/workflows/Consumption%20-%20Budgets/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.consumption.budgets.yml) | | | | | | | | 92 | +| 31 | container-instance

container-group | [![ContainerInstance - ContainerGroups](https://github.com/Azure/ResourceModules/workflows/ContainerInstance%20-%20ContainerGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.containerinstance.containergroups.yml) | | | :white_check_mark: | | | | | 163 | +| 32 | container-registry

registry | [![ContainerRegistry - Registries](https://github.com/Azure/ResourceModules/workflows/ContainerRegistry%20-%20Registries/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.containerregistry.registries.yml) | | | :white_check_mark: | | | | [L1:3] | 430 | +| 33 | container-service

managed-cluster | [![ContainerService - ManagedClusters](https://github.com/Azure/ResourceModules/workflows/ContainerService%20-%20ManagedClusters/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.containerservice.managedclusters.yml) | | | :white_check_mark: | | | | [L1:1] | 664 | +| 34 | data-factory

factory | [![DataFactory - Factories](https://github.com/Azure/ResourceModules/workflows/DataFactory%20-%20Factories/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.datafactory.factories.yml) | | | :white_check_mark: | | | | [L1:2, L2:1] | 318 | +| 35 | data-protection

backup-vault | [![DataProtection - BackupVaults](https://github.com/Azure/ResourceModules/workflows/DataProtection%20-%20BackupVaults/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.dataprotection.backupvaults.yml) | | | :white_check_mark: | | | | [L1:1] | 156 | +| 36 | databricks

access-connector | [![Databricks - Access Connectors](https://github.com/Azure/ResourceModules/workflows/Databricks%20-%20Access%20Connectors/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.databricks.accessconnectors.yml) | | | :white_check_mark: | | | | | 104 | +| 37 | databricks

workspace | [![Databricks - Workspaces](https://github.com/Azure/ResourceModules/workflows/Databricks%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.databricks.workspaces.yml) | | | :white_check_mark: | | | | | 376 | +| 38 | db-for-my-sql

flexible-server | [![DbForMySQL - FlexibleServers](https://github.com/Azure/ResourceModules/workflows/DbForMySQL%20-%20FlexibleServers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.dbformysql.flexibleservers.yml) | | | :white_check_mark: | | | | [L1:3] | 370 | +| 39 | db-for-postgre-sql

flexible-server | [![DbForPostgreSQL - FlexibleServers](https://github.com/Azure/ResourceModules/workflows/DbForPostgreSQL%20-%20FlexibleServers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.dbforpostgresql.flexibleservers.yml) | | | :white_check_mark: | | | | [L1:4] | 364 | +| 40 | desktop-virtualization

application-group | [![DesktopVirtualization - ApplicationGroups](https://github.com/Azure/ResourceModules/workflows/DesktopVirtualization%20-%20ApplicationGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.desktopvirtualization.applicationgroups.yml) | | | :white_check_mark: | | | | [L1:1] | 191 | +| 41 | desktop-virtualization

host-pool | [![DesktopVirtualization - HostPools](https://github.com/Azure/ResourceModules/workflows/DesktopVirtualization%20-%20HostPools/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.desktopvirtualization.hostpools.yml) | | | :white_check_mark: | | | | | 281 | +| 42 | desktop-virtualization

scaling-plan | [![DesktopVirtualization - Scalingplans](https://github.com/Azure/ResourceModules/workflows/DesktopVirtualization%20-%20Scalingplans/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.desktopvirtualization.scalingplans.yml) | | | :white_check_mark: | | | | | 200 | +| 43 | desktop-virtualization

workspace | [![DesktopVirtualization - Workspaces](https://github.com/Azure/ResourceModules/workflows/DesktopVirtualization%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.desktopvirtualization.workspaces.yml) | | | :white_check_mark: | | | | | 161 | +| 44 | dev-test-lab

lab | [![DevTestLab - Labs](https://github.com/Azure/ResourceModules/workflows/DevTestLab%20-%20Labs/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.devtestlab.labs.yml) | | | :white_check_mark: | | | | [L1:6, L2:1] | 295 | +| 45 | digital-twins

digital-twins-instance | [![DigitalTwins - DigitalTwinsInstances](https://github.com/Azure/ResourceModules/workflows/DigitalTwins%20-%20DigitalTwinsInstances/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.digitaltwins.digitaltwinsinstances.yml) | | | :white_check_mark: | | | | [L1:3] | 292 | +| 46 | document-db

database-account | [![DocumentDB - DatabaseAccounts](https://github.com/Azure/ResourceModules/workflows/DocumentDB%20-%20DatabaseAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.documentdb.databaseaccounts.yml) | | | :white_check_mark: | | | | [L1:3, L2:3] | 400 | +| 47 | event-grid

domain | [![EventGrid - Domains](https://github.com/Azure/ResourceModules/workflows/EventGrid%20-%20Domains/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.eventgrid.domains.yml) | | | :white_check_mark: | | | | [L1:1] | 248 | +| 48 | event-grid

system-topic | [![EventGrid - System Topics](https://github.com/Azure/ResourceModules/workflows/EventGrid%20-%20System%20Topics/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.eventgrid.systemtopics.yml) | | | :white_check_mark: | | | | [L1:1] | 193 | +| 49 | event-grid

topic | [![EventGrid - Topics](https://github.com/Azure/ResourceModules/workflows/EventGrid%20-%20Topics/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.eventgrid.topics.yml) | | | :white_check_mark: | | | | [L1:1] | 252 | +| 50 | event-hub

namespace | [![EventHub - Namespaces](https://github.com/Azure/ResourceModules/workflows/EventHub%20-%20Namespaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.eventhub.namespaces.yml) | | | :white_check_mark: | | | | [L1:4, L2:2] | 397 | +| 51 | health-bot

health-bot | [![HealthBot - HealthBots](https://github.com/Azure/ResourceModules/workflows/HealthBot%20-%20HealthBots/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.healthbot.healthbots.yml) | | | :white_check_mark: | | | | | 112 | +| 52 | healthcare-apis

workspace | [![HealthcareApis - Workspaces](https://github.com/Azure/ResourceModules/workflows/HealthcareApis%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.healthcareapis.workspaces.yml) | | | :white_check_mark: | | | | [L1:3, L2:1] | 198 | +| 53 | insights

action-group | [![Insights - ActionGroups](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20ActionGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.actiongroups.yml) | | | :white_check_mark: | | | | | 115 | +| 54 | insights

activity-log-alert | [![Insights - ActivityLogAlerts](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20ActivityLogAlerts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.activitylogalerts.yml) | | | :white_check_mark: | | | | | 104 | +| 55 | insights

component | [![Insights - Components](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20Components/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.components.yml) | | | :white_check_mark: | | | | | 184 | +| 56 | insights

data-collection-endpoint | [![Insights - DataCollectionEndpoints](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20DataCollectionEndpoints/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.datacollectionendpoints.yml) | | | :white_check_mark: | | | | | 120 | +| 57 | insights

data-collection-rule | [![Insights - DataCollectionRules](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20DataCollectionRules/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.datacollectionrules.yml) | | | :white_check_mark: | | | | | 129 | +| 58 | insights

diagnostic-setting | [![Insights - DiagnosticSettings](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20DiagnosticSettings/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.diagnosticsettings.yml) | | | | | | | | 91 | +| 59 | insights

metric-alert | [![Insights - MetricAlerts](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20MetricAlerts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.metricalerts.yml) | | | :white_check_mark: | | | | | 152 | +| 60 | insights

private-link-scope | [![Insights - PrivateLinkScopes](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20PrivateLinkScopes/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.privatelinkscopes.yml) | | | :white_check_mark: | | | | [L1:1] | 172 | +| 61 | insights

scheduled-query-rule | [![Insights - ScheduledQueryRules](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20ScheduledQueryRules/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.scheduledqueryrules.yml) | | | :white_check_mark: | | | | | 136 | +| 62 | insights

webtest | [![Insights - Web Tests](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20Web%20Tests/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.webtests.yml) | | | | | | | | 152 | +| 63 | key-vault

vault | [![KeyVault - Vaults](https://github.com/Azure/ResourceModules/workflows/KeyVault%20-%20Vaults/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.keyvault.vaults.yml) | | | :white_check_mark: | | | | [L1:3] | 347 | +| 64 | kubernetes-configuration

extension | [![KubernetesConfiguration - Extensions](https://github.com/Azure/ResourceModules/workflows/KubernetesConfiguration%20-%20Extensions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.kubernetesconfiguration.extensions.yml) | | | | | | | | 88 | +| 65 | kubernetes-configuration

flux-configuration | [![KubernetesConfiguration - FluxConfigurations](https://github.com/Azure/ResourceModules/workflows/KubernetesConfiguration%20-%20FluxConfigurations/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.kubernetesconfiguration.fluxconfigurations.yml) | | | | | | | | 71 | +| 66 | logic

workflow | [![Logic - Workflows](https://github.com/Azure/ResourceModules/workflows/Logic%20-%20Workflows/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.logic.workflows.yml) | | | :white_check_mark: | | | | | 227 | +| 67 | machine-learning-services

workspace | [![MachineLearningServices - Workspaces](https://github.com/Azure/ResourceModules/workflows/MachineLearningServices%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.machinelearningservices.workspaces.yml) | | | :white_check_mark: | | | | [L1:1] | 352 | +| 68 | maintenance

maintenance-configuration | [![Maintenance - MaintenanceConfigurations](https://github.com/Azure/ResourceModules/workflows/Maintenance%20-%20MaintenanceConfigurations/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.maintenance.maintenanceconfigurations.yml) | | | :white_check_mark: | | | | | 136 | +| 69 | managed-identity

user-assigned-identity | [![ManagedIdentity - UserAssignedIdentities](https://github.com/Azure/ResourceModules/workflows/ManagedIdentity%20-%20UserAssignedIdentities/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.managedidentity.userassignedidentities.yml) | | | :white_check_mark: | | | | [L1:1] | 113 | +| 70 | managed-services

registration-definition | [![ManagedServices - RegistrationDefinitions](https://github.com/Azure/ResourceModules/workflows/ManagedServices%20-%20RegistrationDefinitions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.managedservices.registrationdefinitions.yml) | | | | | | | | 67 | +| 71 | management

management-group | [![Management - ManagementGroups](https://github.com/Azure/ResourceModules/workflows/Management%20-%20ManagementGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.management.managementgroups.yml) | | | | | | | | 50 | +| 72 | net-app

net-app-account | [![NetApp - NetAppAccounts](https://github.com/Azure/ResourceModules/workflows/NetApp%20-%20NetAppAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.netapp.netappaccounts.yml) | | | :white_check_mark: | | | | [L1:1, L2:1] | 147 | +| 73 | network

application-gateway | [![Network - ApplicationGateways](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ApplicationGateways/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.applicationgateways.yml) | | | :white_check_mark: | | | | | 416 | +| 74 | network

application-gateway-web-application-firewall-policy | [![Network - ApplicationGatewayWebApplicationFirewallPolicies](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ApplicationGatewayWebApplicationFirewallPolicies/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.applicationgatewaywebapplicationfirewallpolicies.yml) | | | :white_check_mark: | | | | | 47 | +| 75 | network

application-security-group | [![Network - ApplicationSecurityGroups](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ApplicationSecurityGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.applicationsecuritygroups.yml) | | | :white_check_mark: | | | | | 94 | +| 76 | network

azure-firewall | [![Network - AzureFirewalls](https://github.com/Azure/ResourceModules/workflows/Network%20-%20AzureFirewalls/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.azurefirewalls.yml) | | | :white_check_mark: | | | :white_check_mark: | | 335 | +| 77 | network

bastion-host | [![Network - BastionHosts](https://github.com/Azure/ResourceModules/workflows/Network%20-%20BastionHosts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.bastionhosts.yml) | | | :white_check_mark: | | | :white_check_mark: | | 268 | +| 78 | network

connection | [![Network - Connections](https://github.com/Azure/ResourceModules/workflows/Network%20-%20Connections/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.connections.yml) | | | :white_check_mark: | | | | | 147 | +| 79 | network

ddos-protection-plan | [![Network - DdosProtectionPlans](https://github.com/Azure/ResourceModules/workflows/Network%20-%20DdosProtectionPlans/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.ddosprotectionplans.yml) | | | :white_check_mark: | | | | | 95 | +| 80 | network

dns-forwarding-ruleset | [![Network - DNS Forwarding Rulesets](https://github.com/Azure/ResourceModules/workflows/Network%20-%20DNS%20Forwarding%20Rulesets/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.dnsforwardingrulesets.yml) | | | :white_check_mark: | | | | [L1:2] | 126 | +| 81 | network

dns-resolver | [![Network - DNS Resolvers](https://github.com/Azure/ResourceModules/workflows/Network%20-%20DNS%20Resolvers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.dnsresolvers.yml) | | | :white_check_mark: | | | | | 137 | +| 82 | network

dns-zone | [![Network - Public DnsZones](https://github.com/Azure/ResourceModules/workflows/Network%20-%20Public%20DnsZones/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.dnszones.yml) | | | :white_check_mark: | | | | [L1:10] | 248 | +| 83 | network

express-route-circuit | [![Network - ExpressRouteCircuits](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ExpressRouteCircuits/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.expressroutecircuits.yml) | | | :white_check_mark: | | | | | 228 | +| 84 | network

express-route-gateway | [![Network - ExpressRouteGateways](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ExpressRouteGateways/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.expressroutegateways.yml) | | | :white_check_mark: | | | | | 117 | +| 85 | network

firewall-policy | [![Network - FirewallPolicies](https://github.com/Azure/ResourceModules/workflows/Network%20-%20FirewallPolicies/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.firewallpolicies.yml) | | | :white_check_mark: | | | | [L1:1] | 166 | +| 86 | network

front-door | [![Network - Frontdoors](https://github.com/Azure/ResourceModules/workflows/Network%20-%20Frontdoors/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.frontdoors.yml) | | | :white_check_mark: | | | | | 181 | +| 87 | network

front-door-web-application-firewall-policy | [![Network - FrontDoorWebApplicationFirewallPolicies](https://github.com/Azure/ResourceModules/workflows/Network%20-%20FrontDoorWebApplicationFirewallPolicies/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.frontdoorwebapplicationfirewallpolicies.yml) | | | :white_check_mark: | | | | | 152 | +| 88 | network

ip-group | [![Network - IpGroups](https://github.com/Azure/ResourceModules/workflows/Network%20-%20IpGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.ipgroups.yml) | | | :white_check_mark: | | | | | 100 | +| 89 | network

load-balancer | [![Network - LoadBalancers](https://github.com/Azure/ResourceModules/workflows/Network%20-%20LoadBalancers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.loadbalancers.yml) | | | :white_check_mark: | | | | [L1:2] | 272 | +| 90 | network

local-network-gateway | [![Network - LocalNetworkGateways](https://github.com/Azure/ResourceModules/workflows/Network%20-%20LocalNetworkGateways/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.localnetworkgateways.yml) | | | :white_check_mark: | | | | | 120 | +| 91 | network

nat-gateway | [![Network - NatGateways](https://github.com/Azure/ResourceModules/workflows/Network%20-%20NatGateways/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.natgateways.yml) | | | :white_check_mark: | | | | | 181 | +| 92 | network

network-interface | [![Network - NetworkInterfaces](https://github.com/Azure/ResourceModules/workflows/Network%20-%20NetworkInterfaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.networkinterfaces.yml) | | | :white_check_mark: | | | | | 198 | +| 93 | network

network-manager | [![Network - Network Managers](https://github.com/Azure/ResourceModules/workflows/Network%20-%20Network%20Managers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.networkmanagers.yml) | | | :white_check_mark: | | | | [L1:4, L2:2, L3:1] | 165 | +| 94 | network

network-security-group | [![Network - NetworkSecurityGroups](https://github.com/Azure/ResourceModules/workflows/Network%20-%20NetworkSecurityGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.networksecuritygroups.yml) | | | :white_check_mark: | | | | [L1:1] | 188 | +| 95 | network

network-watcher | [![Network - NetworkWatchers](https://github.com/Azure/ResourceModules/workflows/Network%20-%20NetworkWatchers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.networkwatchers.yml) | | | :white_check_mark: | | | | [L1:2] | 129 | +| 96 | network

private-dns-zone | [![Network - PrivateDnsZones](https://github.com/Azure/ResourceModules/workflows/Network%20-%20PrivateDnsZones/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.privatednszones.yml) | | | :white_check_mark: | | | | [L1:9] | 226 | +| 97 | network

private-endpoint | [![Network - PrivateEndpoints](https://github.com/Azure/ResourceModules/workflows/Network%20-%20PrivateEndpoints/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.privateendpoints.yml) | | | | | | | [L1:1] | 149 | +| 98 | network

private-link-service | [![Network - PrivateLinkServices](https://github.com/Azure/ResourceModules/workflows/Network%20-%20PrivateLinkServices/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.privatelinkservices.yml) | | | :white_check_mark: | | | | | 121 | +| 99 | network

public-ip-address | [![Network - PublicIpAddresses](https://github.com/Azure/ResourceModules/workflows/Network%20-%20PublicIpAddresses/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.publicipaddresses.yml) | | | :white_check_mark: | | | | | 214 | +| 100 | network

public-ip-prefix | [![Network - PublicIpPrefixes](https://github.com/Azure/ResourceModules/workflows/Network%20-%20PublicIpPrefixes/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.publicipprefixes.yml) | | | :white_check_mark: | | | | | 109 | +| 101 | network

route-table | [![Network - RouteTables](https://github.com/Azure/ResourceModules/workflows/Network%20-%20RouteTables/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.routetables.yml) | | | :white_check_mark: | | | | | 102 | +| 102 | network

service-endpoint-policy | [![Network - ServiceEndpointPolicies](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ServiceEndpointPolicies/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.serviceendpointpolicies.yml) | | | :white_check_mark: | | | | | 105 | +| 103 | network

trafficmanagerprofile | [![Network - TrafficManagerProfiles](https://github.com/Azure/ResourceModules/workflows/Network%20-%20TrafficManagerProfiles/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.trafficmanagerprofiles.yml) | | | :white_check_mark: | | | | | 195 | +| 104 | network

virtual-hub | [![Network - VirtualHubs](https://github.com/Azure/ResourceModules/workflows/Network%20-%20VirtualHubs/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.virtualhubs.yml) | | | :white_check_mark: | | | | [L1:2] | 151 | +| 105 | network

virtual-network | [![Network - VirtualNetworks](https://github.com/Azure/ResourceModules/workflows/Network%20-%20VirtualNetworks/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.virtualnetworks.yml) | | | :white_check_mark: | | | | [L1:2] | 276 | +| 106 | network

virtual-network-gateway | [![Network - VirtualNetworkGateways](https://github.com/Azure/ResourceModules/workflows/Network%20-%20VirtualNetworkGateways/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.virtualnetworkgateways.yml) | | | :white_check_mark: | | | | [L1:1] | 403 | +| 107 | network

virtual-wan | [![Network - VirtualWans](https://github.com/Azure/ResourceModules/workflows/Network%20-%20VirtualWans/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.virtualwans.yml) | | | :white_check_mark: | | | | | 112 | +| 108 | network

vpn-gateway | [![Network - VPNGateways](https://github.com/Azure/ResourceModules/workflows/Network%20-%20VPNGateways/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.vpngateways.yml) | | | :white_check_mark: | | | | [L1:2] | 114 | +| 109 | network

vpn-site | [![Network - VPN Sites](https://github.com/Azure/ResourceModules/workflows/Network%20-%20VPN%20Sites/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.vpnsites.yml) | | | :white_check_mark: | | | | | 124 | +| 110 | operational-insights

workspace | [![OperationalInsights - Workspaces](https://github.com/Azure/ResourceModules/workflows/OperationalInsights%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.operationalinsights.workspaces.yml) | | | :white_check_mark: | | | | [L1:7] | 344 | +| 111 | operations-management

solution | [![OperationsManagement - Solutions](https://github.com/Azure/ResourceModules/workflows/OperationsManagement%20-%20Solutions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.operationsmanagement.solutions.yml) | | | | | | | | 53 | +| 112 | policy-insights

remediation | [![PolicyInsights - Remediations](https://github.com/Azure/ResourceModules/workflows/PolicyInsights%20-%20Remediations/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.policyinsights.remediations.yml) | | | | | | | [L1:3] | 106 | +| 113 | power-bi-dedicated

capacity | [![PowerBiDedicated - Capacities](https://github.com/Azure/ResourceModules/workflows/PowerBiDedicated%20-%20Capacities/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.powerbidedicated.capacities.yml) | | | :white_check_mark: | | | | | 133 | +| 114 | purview

account | [![Purview - Accounts](https://github.com/Azure/ResourceModules/workflows/Purview%20-%20Accounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.purview.accounts.yml) | | | :white_check_mark: | | | | | 311 | +| 115 | recovery-services

vault | [![RecoveryServices - Vaults](https://github.com/Azure/ResourceModules/workflows/RecoveryServices%20-%20Vaults/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.recoveryservices.vaults.yml) | | | :white_check_mark: | | | | [L1:7, L2:2, L3:2] | 351 | +| 116 | relay

namespace | [![Relay - Namespaces](https://github.com/Azure/ResourceModules/workflows/Relay%20-%20Namespaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.relay.namespaces.yml) | | | :white_check_mark: | | | | [L1:4, L2:2] | 330 | +| 117 | resource-graph

query | [![ResourceGraph - Queries](https://github.com/Azure/ResourceModules/workflows/ResourceGraph%20-%20Queries/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.resourcegraph.queries.yml) | | | :white_check_mark: | | | | | 101 | +| 118 | resources

deployment-script | [![Resources - DeploymentScripts](https://github.com/Azure/ResourceModules/workflows/Resources%20-%20DeploymentScripts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.resources.deploymentscripts.yml) | | | :white_check_mark: | | | | | 128 | +| 119 | resources

resource-group | [![Resources - ResourceGroups](https://github.com/Azure/ResourceModules/workflows/Resources%20-%20ResourceGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.resources.resourcegroups.yml) | | | :white_check_mark: | | | | [L1:1] | 101 | +| 120 | resources

tags | [![Resources - Tags](https://github.com/Azure/ResourceModules/workflows/Resources%20-%20Tags/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.resources.tags.yml) | | | :white_check_mark: | | | | [L1:2] | 54 | +| 121 | search

search-service | [![Search - SearchServices](https://github.com/Azure/ResourceModules/workflows/Search%20-%20SearchServices/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.search.searchservices.yml) | | | :white_check_mark: | | | | [L1:1] | 313 | +| 122 | security

azure-security-center | [![Security - AzureSecurityCenter](https://github.com/Azure/ResourceModules/workflows/Security%20-%20AzureSecurityCenter/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.security.azuresecuritycenter.yml) | | | | | | | | 221 | +| 123 | service-bus

namespace | [![ServiceBus - Namespaces](https://github.com/Azure/ResourceModules/workflows/ServiceBus%20-%20Namespaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.servicebus.namespaces.yml) | | | :white_check_mark: | | | | [L1:6, L2:2] | 441 | +| 124 | service-fabric

cluster | [![ServiceFabric - Clusters](https://github.com/Azure/ResourceModules/workflows/ServiceFabric%20-%20Clusters/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.servicefabric.clusters.yml) | | | :white_check_mark: | | | | [L1:1] | 312 | +| 125 | signal-r-service

signal-r | [![SignalRService - SignalR](https://github.com/Azure/ResourceModules/workflows/SignalRService%20-%20SignalR/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.signalrservice.signalr.yml) | | | :white_check_mark: | | | | | 268 | +| 126 | signal-r-service

web-pub-sub | [![SignalRService - WebPubSub](https://github.com/Azure/ResourceModules/workflows/SignalRService%20-%20WebPubSub/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.signalrservice.webpubsub.yml) | | | :white_check_mark: | | | | | 238 | +| 127 | sql

managed-instance | [![Sql - ManagedInstances](https://github.com/Azure/ResourceModules/workflows/Sql%20-%20ManagedInstances/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.sql.managedinstances.yml) | | | :white_check_mark: | | | | [L1:6, L2:3] | 369 | +| 128 | sql

server | [![Sql - Servers](https://github.com/Azure/ResourceModules/workflows/Sql%20-%20Servers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.sql.servers.yml) | | | :white_check_mark: | | | | [L1:8, L2:3] | 376 | +| 129 | storage

storage-account | [![Storage - StorageAccounts](https://github.com/Azure/ResourceModules/workflows/Storage%20-%20StorageAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.storage.storageaccounts.yml) | | | :white_check_mark: | | | | [L1:6, L2:4, L3:1] | 500 | +| 130 | synapse

private-link-hub | [![Synapse - PrivateLinkHubs](https://github.com/Azure/ResourceModules/workflows/Synapse%20-%20PrivateLinkHubs/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.synapse.privatelinkhubs.yml) | | | :white_check_mark: | | | | | 162 | +| 131 | synapse

workspace | [![Synapse - Workspaces](https://github.com/Azure/ResourceModules/workflows/Synapse%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.synapse.workspaces.yml) | | | :white_check_mark: | | | | [L1:3] | 355 | +| 132 | virtual-machine-images

image-template | [![VirtualMachineImages - ImageTemplates](https://github.com/Azure/ResourceModules/workflows/VirtualMachineImages%20-%20ImageTemplates/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.virtualmachineimages.imagetemplates.yml) | | | :white_check_mark: | | | | | 216 | +| 133 | web

connection | [![Web - Connections](https://github.com/Azure/ResourceModules/workflows/Web%20-%20Connections/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.connections.yml) | | | :white_check_mark: | | | | | 118 | +| 134 | web

hosting-environment | [![Web - HostingEnvironments](https://github.com/Azure/ResourceModules/workflows/Web%20-%20HostingEnvironments/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.hostingenvironments.yml) | | | :white_check_mark: | | | | [L1:2] | 258 | +| 135 | web

serverfarm | [![Web - Serverfarms](https://github.com/Azure/ResourceModules/workflows/Web%20-%20Serverfarms/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.serverfarms.yml) | | | :white_check_mark: | | | | | 194 | +| 136 | web

site | [![Web - Sites](https://github.com/Azure/ResourceModules/workflows/Web%20-%20Sites/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.sites.yml) | | | :white_check_mark: | | | | [L1:5, L2:4, L3:1] | 441 | +| 137 | web

static-site | [![Web - StaticSites](https://github.com/Azure/ResourceModules/workflows/Web%20-%20StaticSites/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.staticsites.yml) | | | :white_check_mark: | | | | [L1:3] | 271 | +| Sum | | | 0 | 0 | 119 | 0 | 0 | 2 | 240 | 29361 | ## Legend From f36644d60873a61eedb9c1d165ee2097755ba94c Mon Sep 17 00:00:00 2001 From: ChrisSidebotham-MSFT <48600046+ChrisSidebotham@users.noreply.github.com> Date: Mon, 30 Oct 2023 19:13:07 +0000 Subject: [PATCH 4/7] [Modules] Updating Moved-to-avm.md on Migrated Modules (#4164) * Adding Moved-to-AVM.md * updated readme --- modules/network/dns-forwarding-ruleset/MOVED-TO-AVM.md | 1 + modules/network/dns-forwarding-ruleset/README.md | 2 ++ modules/network/dns-resolver/MOVED-TO-AVM.md | 1 + modules/network/dns-resolver/README.md | 2 ++ modules/network/dns-zone/MOVED-TO-AVM.md | 1 + modules/network/dns-zone/README.md | 2 ++ modules/network/private-dns-zone/MOVED-TO-AVM.md | 1 + modules/network/private-dns-zone/README.md | 2 ++ 8 files changed, 12 insertions(+) create mode 100644 modules/network/dns-forwarding-ruleset/MOVED-TO-AVM.md create mode 100644 modules/network/dns-resolver/MOVED-TO-AVM.md create mode 100644 modules/network/dns-zone/MOVED-TO-AVM.md create mode 100644 modules/network/private-dns-zone/MOVED-TO-AVM.md diff --git a/modules/network/dns-forwarding-ruleset/MOVED-TO-AVM.md b/modules/network/dns-forwarding-ruleset/MOVED-TO-AVM.md new file mode 100644 index 0000000000..cec0941d12 --- /dev/null +++ b/modules/network/dns-forwarding-ruleset/MOVED-TO-AVM.md @@ -0,0 +1 @@ +This module has already been migrated to [AVM](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res). Only the AVM version is expected to receive updates / new features. Please do not work on improving this module in [CARML](https://aka.ms/carml). diff --git a/modules/network/dns-forwarding-ruleset/README.md b/modules/network/dns-forwarding-ruleset/README.md index f502927b87..b846abe7d3 100644 --- a/modules/network/dns-forwarding-ruleset/README.md +++ b/modules/network/dns-forwarding-ruleset/README.md @@ -1,5 +1,7 @@ # Dns Forwarding Rulesets `[Microsoft.Network/dnsForwardingRulesets]` +> This module has already been migrated to [AVM](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res). Only the AVM version is expected to receive updates / new features. Please do not work on improving this module in [CARML](https://aka.ms/carml). + This template deploys an dns forwarding ruleset. ## Navigation diff --git a/modules/network/dns-resolver/MOVED-TO-AVM.md b/modules/network/dns-resolver/MOVED-TO-AVM.md new file mode 100644 index 0000000000..cec0941d12 --- /dev/null +++ b/modules/network/dns-resolver/MOVED-TO-AVM.md @@ -0,0 +1 @@ +This module has already been migrated to [AVM](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res). Only the AVM version is expected to receive updates / new features. Please do not work on improving this module in [CARML](https://aka.ms/carml). diff --git a/modules/network/dns-resolver/README.md b/modules/network/dns-resolver/README.md index 3846d4fbc5..992d53a5c0 100644 --- a/modules/network/dns-resolver/README.md +++ b/modules/network/dns-resolver/README.md @@ -1,5 +1,7 @@ # DNS Resolvers `[Microsoft.Network/dnsResolvers]` +> This module has already been migrated to [AVM](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res). Only the AVM version is expected to receive updates / new features. Please do not work on improving this module in [CARML](https://aka.ms/carml). + This module deploys a DNS Resolver. ## Navigation diff --git a/modules/network/dns-zone/MOVED-TO-AVM.md b/modules/network/dns-zone/MOVED-TO-AVM.md new file mode 100644 index 0000000000..cec0941d12 --- /dev/null +++ b/modules/network/dns-zone/MOVED-TO-AVM.md @@ -0,0 +1 @@ +This module has already been migrated to [AVM](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res). Only the AVM version is expected to receive updates / new features. Please do not work on improving this module in [CARML](https://aka.ms/carml). diff --git a/modules/network/dns-zone/README.md b/modules/network/dns-zone/README.md index 75edd92cfa..bf589f09c1 100644 --- a/modules/network/dns-zone/README.md +++ b/modules/network/dns-zone/README.md @@ -1,5 +1,7 @@ # Public DNS Zones `[Microsoft.Network/dnsZones]` +> This module has already been migrated to [AVM](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res). Only the AVM version is expected to receive updates / new features. Please do not work on improving this module in [CARML](https://aka.ms/carml). + This module deploys a Public DNS zone. ## Navigation diff --git a/modules/network/private-dns-zone/MOVED-TO-AVM.md b/modules/network/private-dns-zone/MOVED-TO-AVM.md new file mode 100644 index 0000000000..cec0941d12 --- /dev/null +++ b/modules/network/private-dns-zone/MOVED-TO-AVM.md @@ -0,0 +1 @@ +This module has already been migrated to [AVM](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res). Only the AVM version is expected to receive updates / new features. Please do not work on improving this module in [CARML](https://aka.ms/carml). diff --git a/modules/network/private-dns-zone/README.md b/modules/network/private-dns-zone/README.md index b48571f56a..0191518ff6 100644 --- a/modules/network/private-dns-zone/README.md +++ b/modules/network/private-dns-zone/README.md @@ -1,5 +1,7 @@ # Private DNS Zones `[Microsoft.Network/privateDnsZones]` +> This module has already been migrated to [AVM](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res). Only the AVM version is expected to receive updates / new features. Please do not work on improving this module in [CARML](https://aka.ms/carml). + This module deploys a Private DNS zone. ## Navigation From b61e3b492292796db5640709fd04508891c508d3 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Mon, 30 Oct 2023 23:36:06 +0100 Subject: [PATCH 5/7] Added MOVED-TO-AVM files (#4165) --- modules/batch/batch-account/MOVED-TO-AVM.md | 1 + modules/batch/batch-account/README.md | 2 ++ modules/cognitive-services/account/MOVED-TO-AVM.md | 1 + modules/cognitive-services/account/README.md | 2 ++ modules/insights/action-group/MOVED-TO-AVM.md | 1 + modules/insights/action-group/README.md | 2 ++ modules/network/network-interface/MOVED-TO-AVM.md | 1 + modules/network/network-interface/README.md | 2 ++ 8 files changed, 12 insertions(+) create mode 100644 modules/batch/batch-account/MOVED-TO-AVM.md create mode 100644 modules/cognitive-services/account/MOVED-TO-AVM.md create mode 100644 modules/insights/action-group/MOVED-TO-AVM.md create mode 100644 modules/network/network-interface/MOVED-TO-AVM.md diff --git a/modules/batch/batch-account/MOVED-TO-AVM.md b/modules/batch/batch-account/MOVED-TO-AVM.md new file mode 100644 index 0000000000..cec0941d12 --- /dev/null +++ b/modules/batch/batch-account/MOVED-TO-AVM.md @@ -0,0 +1 @@ +This module has already been migrated to [AVM](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res). Only the AVM version is expected to receive updates / new features. Please do not work on improving this module in [CARML](https://aka.ms/carml). diff --git a/modules/batch/batch-account/README.md b/modules/batch/batch-account/README.md index 5c724d1f23..66ec1ea280 100644 --- a/modules/batch/batch-account/README.md +++ b/modules/batch/batch-account/README.md @@ -1,5 +1,7 @@ # Batch Accounts `[Microsoft.Batch/batchAccounts]` +> This module has already been migrated to [AVM](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res). Only the AVM version is expected to receive updates / new features. Please do not work on improving this module in [CARML](https://aka.ms/carml). + This module deploys a Batch Account. ## Navigation diff --git a/modules/cognitive-services/account/MOVED-TO-AVM.md b/modules/cognitive-services/account/MOVED-TO-AVM.md new file mode 100644 index 0000000000..cec0941d12 --- /dev/null +++ b/modules/cognitive-services/account/MOVED-TO-AVM.md @@ -0,0 +1 @@ +This module has already been migrated to [AVM](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res). Only the AVM version is expected to receive updates / new features. Please do not work on improving this module in [CARML](https://aka.ms/carml). diff --git a/modules/cognitive-services/account/README.md b/modules/cognitive-services/account/README.md index 1ef76d0cbb..a55ed7a0ae 100644 --- a/modules/cognitive-services/account/README.md +++ b/modules/cognitive-services/account/README.md @@ -1,5 +1,7 @@ # Cognitive Services `[Microsoft.CognitiveServices/accounts]` +> This module has already been migrated to [AVM](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res). Only the AVM version is expected to receive updates / new features. Please do not work on improving this module in [CARML](https://aka.ms/carml). + This module deploys a Cognitive Service. ## Navigation diff --git a/modules/insights/action-group/MOVED-TO-AVM.md b/modules/insights/action-group/MOVED-TO-AVM.md new file mode 100644 index 0000000000..cec0941d12 --- /dev/null +++ b/modules/insights/action-group/MOVED-TO-AVM.md @@ -0,0 +1 @@ +This module has already been migrated to [AVM](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res). Only the AVM version is expected to receive updates / new features. Please do not work on improving this module in [CARML](https://aka.ms/carml). diff --git a/modules/insights/action-group/README.md b/modules/insights/action-group/README.md index 2b2d2fcbfa..107e2c2fd1 100644 --- a/modules/insights/action-group/README.md +++ b/modules/insights/action-group/README.md @@ -1,5 +1,7 @@ # Action Groups `[Microsoft.Insights/actionGroups]` +> This module has already been migrated to [AVM](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res). Only the AVM version is expected to receive updates / new features. Please do not work on improving this module in [CARML](https://aka.ms/carml). + This module deploys an Action Group. ## Navigation diff --git a/modules/network/network-interface/MOVED-TO-AVM.md b/modules/network/network-interface/MOVED-TO-AVM.md new file mode 100644 index 0000000000..cec0941d12 --- /dev/null +++ b/modules/network/network-interface/MOVED-TO-AVM.md @@ -0,0 +1 @@ +This module has already been migrated to [AVM](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res). Only the AVM version is expected to receive updates / new features. Please do not work on improving this module in [CARML](https://aka.ms/carml). diff --git a/modules/network/network-interface/README.md b/modules/network/network-interface/README.md index 2af3a8f2a0..678d9fd744 100644 --- a/modules/network/network-interface/README.md +++ b/modules/network/network-interface/README.md @@ -1,5 +1,7 @@ # Network Interface `[Microsoft.Network/networkInterfaces]` +> This module has already been migrated to [AVM](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res). Only the AVM version is expected to receive updates / new features. Please do not work on improving this module in [CARML](https://aka.ms/carml). + This module deploys a Network Interface. ## Navigation From d57068f2ee07f9d32f8f204d069b4ed08fa5e6fd Mon Sep 17 00:00:00 2001 From: Kris Baranek Date: Tue, 31 Oct 2023 13:17:48 +0100 Subject: [PATCH 6/7] [Modules] Updated identities to UDT as per AVM specs - Batch 1 (#4124) * Updated API Management module * Updated Container App module * Updating Configuration Store module (ongoing) * Updated Configuration Store module * Updated Automation Account module * Comment headers formatted * Readme/ARM for first four modules * Updated Batch Account module * Fixed parameter descriptions * Updated Readme and ARM * Updated Redis Cache module * Container App - Fixed parameter descriptions * Updated Cognitive Services module * Updated VMSS module * Updated Container Group module * Updated Container Registry module * Updated Data Factory module * Updated Event Grid / System Topic module * Updated EventHub Namespace module * [Modules] Resolved conflicts (#4129) * [Modules] Migrated batch [1/4] to AVM RBAC (#4125) * Updated first badge of templates (readmes pending) * Update to latest * Compiled templates * Compiled templates * Compiled first few readmes * Updated test files * Updated readmes * Reduced roles * Updated templates * Rollback different branches' changes * Updated nic & pip * Fixed test file * Refreshed vm * Push updated Readme file(s) * Updated templates * Updated templates --------- Co-authored-by: CARMLPipelinePrincipal * Clean-up, some fixes * Removed Azure Firewall changes from branch * Update API common test file * Update API common test file2 * Updated Recovery Services Vault module * Updated ServiceBus Namespace module * Updated SQL Managed Instance module * Updated SQL Server module * Updated Static Website module * Updated Web Site module * Updated website slot readme/arm * Redis Cache - Testing with two identities * Configuration Store module - Testing with two identities * Updated Signal-R WebPub Sub module * Updated Barch module to support only one type of identity * Updated AKS module * Updated Databricks Access Connector module * Updated Disk Encryption Set module * Updated Search Service module * Updated Backup Vault module * Updated Firewall Policy module * Updated MySQL Flexible server module * MySQL Flexible server module - namePrefix reset * Updated Health Bot module * Updated NetApp Account module * Updated App Gateway module * Updated Deployment Script module * Updated PostgreSQL Flexible Server module * Fixed description of userAssignedResourcesIds * Updated Storage Account module * Updated Web Hosting Environment module * Updated Log Analytics Workspace module * Updated Logic Workflow module * Updated ML Workspace module * Updated ML Workspace Compute module * Updated Cosmos DB module * Updated VM module * Updated Digital Twins module * Updated Healthcare APIs module * Updated DevTest Lab module * Updated PurView Account module * Fixed Digital Twins missing references * Fixed DevTest Lab formattedManagementIdentities ref * Purview fix * Purview fix 2 * Purview updated ARM * SQL MI fix * SQL MI updated ARM * SQL MI removed new output * Small fixes * Fixed SQL Server module * DigitalTwins - fixed params * Digital Twins - reset to main * mySQL - updated param description * postgreSQL - updated param description * mySQL - updated conditional param description * postgreSQL - updated conditional param description * Updated param description for "one identity only" modules * Disk Encryption Set - updated keyVaultPermissions implementation * Removed identity from Gremlin DB * Web Hosting Env - changed the way how to suppress warning --------- Co-authored-by: Alexander Sehr Co-authored-by: CARMLPipelinePrincipal --- .../service/.test/common/main.test.bicep | 3 + .../service/.test/max/main.test.bicep | 8 +- modules/api-management/service/README.md | 79 +++++---- modules/api-management/service/main.bicep | 25 +-- modules/api-management/service/main.json | 47 ++++-- .../.test/common/main.test.bicep | 8 +- .../.test/encr/main.test.bicep | 6 +- .../configuration-store/README.md | 91 ++++++----- .../.bicep/nested_roleAssignments.bicep | 70 -------- .../configuration-store/main.bicep | 27 ++-- .../configuration-store/main.json | 50 +++--- .../.test/common/main.test.bicep | 6 +- modules/app/container-app/README.md | 64 +++++--- modules/app/container-app/main.bicep | 26 +-- modules/app/container-app/main.json | 50 ++++-- .../.test/common/main.test.bicep | 8 +- .../.test/encr/main.test.bicep | 6 +- .../automation/automation-account/README.md | 83 ++++++---- .../automation/automation-account/main.bicep | 25 +-- .../automation/automation-account/main.json | 47 ++++-- .../.test/common/main.test.bicep | 4 +- .../batch-account/.test/encr/main.test.bicep | 6 +- modules/batch/batch-account/README.md | 76 +++++---- modules/batch/batch-account/main.bicep | 28 ++-- modules/batch/batch-account/main.json | 53 ++++-- .../redis/.test/common/dependencies.bicep | 11 ++ .../cache/redis/.test/common/main.test.bicep | 8 +- modules/cache/redis/README.md | 62 ++++--- modules/cache/redis/main.bicep | 28 ++-- modules/cache/redis/main.json | 53 ++++-- .../account/.test/common/main.test.bicep | 8 +- .../account/.test/encr/main.test.bicep | 6 +- .../account/.test/speech/main.test.bicep | 8 +- modules/cognitive-services/account/README.md | 117 ++++++++------ modules/cognitive-services/account/main.bicep | 25 +-- modules/cognitive-services/account/main.json | 47 ++++-- .../.test/accessPolicies/main.test.bicep | 8 +- .../.test/common/main.test.bicep | 7 +- modules/compute/disk-encryption-set/README.md | 100 ++++++------ .../compute/disk-encryption-set/main.bicep | 35 ++-- modules/compute/disk-encryption-set/main.json | 58 ++++--- .../.test/linux/main.test.bicep | 10 +- .../.test/windows/main.test.bicep | 10 +- .../virtual-machine-scale-set/README.md | 97 ++++++----- .../virtual-machine-scale-set/main.bicep | 25 +-- .../virtual-machine-scale-set/main.json | 47 ++++-- .../.test/linux/main.test.bicep | 8 +- .../.test/windows/main.test.bicep | 8 +- modules/compute/virtual-machine/README.md | 97 ++++++----- modules/compute/virtual-machine/main.bicep | 39 ++--- modules/compute/virtual-machine/main.json | 47 ++++-- .../.test/common/main.test.bicep | 8 +- .../.test/encr/main.test.bicep | 8 +- .../.test/private/main.test.bicep | 8 +- .../container-group/README.md | 119 ++++++++------ .../container-group/main.bicep | 25 +-- .../container-group/main.json | 47 ++++-- .../registry/.test/common/main.test.bicep | 10 +- .../registry/.test/encr/main.test.bicep | 6 +- modules/container-registry/registry/README.md | 91 ++++++----- .../container-registry/registry/main.bicep | 25 +-- modules/container-registry/registry/main.json | 47 ++++-- .../.test/azure/main.test.bicep | 6 +- .../.test/kubenet/main.test.bicep | 6 +- .../managed-cluster/.test/min/main.test.bicep | 4 +- .../.test/priv/main.test.bicep | 6 +- .../managed-cluster/README.md | 115 ++++++++----- .../managed-cluster/main.bicep | 27 ++-- .../managed-cluster/main.json | 50 +++--- .../factory/.test/common/main.test.bicep | 8 +- modules/data-factory/factory/README.md | 71 ++++---- modules/data-factory/factory/main.bicep | 25 +-- modules/data-factory/factory/main.json | 47 ++++-- .../backup-vault/.test/common/main.test.bicep | 4 +- .../data-protection/backup-vault/README.md | 41 +++-- .../data-protection/backup-vault/main.bicep | 17 +- .../data-protection/backup-vault/main.json | 29 ++-- .../.test/common/main.test.bicep | 8 +- modules/databricks/access-connector/README.md | 70 ++++---- .../databricks/access-connector/main.bicep | 26 +-- modules/databricks/access-connector/main.json | 50 ++++-- .../.test/private/main.test.bicep | 6 +- .../.test/public/main.test.bicep | 8 +- .../db-for-my-sql/flexible-server/README.md | 71 +++++--- .../db-for-my-sql/flexible-server/main.bicep | 17 +- .../db-for-my-sql/flexible-server/main.json | 28 +++- .../.test/public/main.test.bicep | 6 +- .../flexible-server/README.md | 47 ++++-- .../flexible-server/main.bicep | 21 ++- .../flexible-server/main.json | 31 ++-- .../lab/.test/common/main.test.bicep | 12 +- modules/dev-test-lab/lab/README.md | 64 +++++--- modules/dev-test-lab/lab/main.bicep | 32 ++-- modules/dev-test-lab/lab/main.json | 52 ++++-- .../.test/gremlindb/main.test.bicep | 4 +- .../.test/mongodb/main.test.bicep | 4 +- .../.test/sqldb/main.test.bicep | 6 +- .../document-db/database-account/README.md | 89 ++++++---- .../gremlin-database/README.md | 16 -- .../gremlin-database/main.bicep | 24 +-- .../gremlin-database/main.json | 71 +++++--- .../document-db/database-account/main.bicep | 25 +-- .../document-db/database-account/main.json | 118 +++++++++----- .../system-topic/.test/common/main.test.bicep | 3 + modules/event-grid/system-topic/README.md | 53 ++++-- modules/event-grid/system-topic/main.bicep | 25 +-- modules/event-grid/system-topic/main.json | 47 ++++-- .../namespace/.test/common/main.test.bicep | 8 +- .../namespace/.test/encr/main.test.bicep | 8 +- modules/event-hub/namespace/README.md | 97 ++++++----- modules/event-hub/namespace/main.bicep | 25 +-- modules/event-hub/namespace/main.json | 47 ++++-- .../health-bot/.test/common/main.test.bicep | 6 +- modules/health-bot/health-bot/README.md | 47 ++++-- modules/health-bot/health-bot/main.bicep | 17 +- modules/health-bot/health-bot/main.json | 28 +++- .../workspace/.test/common/main.test.bicep | 21 +-- modules/healthcare-apis/workspace/README.md | 40 +++-- .../workspace/dicomservice/README.md | 45 ++++-- .../workspace/dicomservice/main.bicep | 25 +-- .../workspace/dicomservice/main.json | 47 ++++-- .../workspace/fhirservice/README.md | 45 ++++-- .../workspace/fhirservice/main.bicep | 25 +-- .../workspace/fhirservice/main.json | 47 ++++-- .../workspace/iotconnector/README.md | 43 +++-- .../workspace/iotconnector/main.bicep | 25 +-- .../workspace/iotconnector/main.json | 47 ++++-- modules/healthcare-apis/workspace/main.bicep | 9 +- modules/healthcare-apis/workspace/main.json | 152 +++++++++++------- .../workflow/.test/common/main.test.bicep | 6 +- modules/logic/workflow/README.md | 65 +++++--- modules/logic/workflow/main.bicep | 25 +-- modules/logic/workflow/main.json | 47 ++++-- .../workspace/.test/common/main.test.bicep | 16 +- .../workspace/.test/encr/main.test.bicep | 10 +- .../workspace/.test/min/main.test.bicep | 4 +- .../workspace/README.md | 129 +++++++++------ .../workspace/compute/README.md | 45 ++++-- .../workspace/compute/main.bicep | 37 +++-- .../workspace/compute/main.json | 73 ++++++--- .../workspace/main.bicep | 33 ++-- .../workspace/main.json | 125 +++++++++----- .../.test/nfs41/main.test.bicep | 6 +- modules/net-app/net-app-account/README.md | 47 ++++-- modules/net-app/net-app-account/main.bicep | 17 +- modules/net-app/net-app-account/main.json | 28 +++- .../.test/common/main.test.bicep | 6 +- modules/network/application-gateway/README.md | 47 ++++-- .../network/application-gateway/main.bicep | 17 +- modules/network/application-gateway/main.json | 28 +++- modules/network/firewall-policy/README.md | 27 +++- modules/network/firewall-policy/main.bicep | 21 ++- modules/network/firewall-policy/main.json | 45 ++++-- .../workspace/.test/adv/main.test.bicep | 6 +- .../workspace/.test/common/main.test.bicep | 4 +- .../operational-insights/workspace/README.md | 77 +++++---- .../operational-insights/workspace/main.bicep | 25 +-- .../operational-insights/workspace/main.json | 47 ++++-- .../account/.test/common/main.test.bicep | 6 +- modules/purview/account/README.md | 49 ++++-- modules/purview/account/main.bicep | 23 +-- modules/purview/account/main.json | 35 ++-- .../vault/.test/common/main.test.bicep | 6 + modules/recovery-services/vault/README.md | 59 +++++-- modules/recovery-services/vault/main.bicep | 25 +-- modules/recovery-services/vault/main.json | 47 ++++-- .../.test/cli/main.test.bicep | 6 +- .../.test/ps/main.test.bicep | 6 +- modules/resources/deployment-script/README.md | 67 +++++--- .../resources/deployment-script/main.bicep | 17 +- modules/resources/deployment-script/main.json | 28 +++- .../.test/common/main.test.bicep | 4 +- modules/search/search-service/README.md | 40 +++-- modules/search/search-service/main.bicep | 18 ++- modules/search/search-service/main.json | 32 +++- .../namespace/.test/common/main.test.bicep | 8 +- .../namespace/.test/encr/main.test.bicep | 8 +- modules/service-bus/namespace/README.md | 97 ++++++----- modules/service-bus/namespace/main.bicep | 25 +-- modules/service-bus/namespace/main.json | 47 ++++-- .../web-pub-sub/.test/common/main.test.bicep | 4 +- .../signal-r-service/web-pub-sub/README.md | 56 ++++--- .../signal-r-service/web-pub-sub/main.bicep | 32 ++-- .../signal-r-service/web-pub-sub/main.json | 53 ++++-- .../.test/common/main.test.bicep | 10 +- .../.test/vulnAssm/main.test.bicep | 4 +- modules/sql/managed-instance/README.md | 83 ++++++---- modules/sql/managed-instance/main.bicep | 27 ++-- modules/sql/managed-instance/main.json | 49 ++++-- .../sql/server/.test/common/main.test.bicep | 8 +- .../sql/server/.test/vulnAssm/main.test.bicep | 8 +- modules/sql/server/README.md | 97 ++++++----- modules/sql/server/main.bicep | 25 +-- modules/sql/server/main.json | 47 ++++-- .../.test/common/main.test.bicep | 8 +- .../.test/encr/main.test.bicep | 8 +- .../storage-account/.test/nfs/main.test.bicep | 8 +- modules/storage/storage-account/README.md | 123 ++++++++------ modules/storage/storage-account/main.bicep | 26 +-- modules/storage/storage-account/main.json | 47 ++++-- .../.test/asev2/main.test.bicep | 8 +- .../.test/asev3/main.test.bicep | 8 +- modules/web/hosting-environment/README.md | 95 ++++++----- modules/web/hosting-environment/main.bicep | 26 +-- modules/web/hosting-environment/main.json | 43 +++-- .../.test/functionAppCommon/main.test.bicep | 8 +- .../site/.test/webAppCommon/main.test.bicep | 8 +- modules/web/site/README.md | 97 ++++++----- modules/web/site/main.bicep | 30 ++-- modules/web/site/main.json | 99 ++++++++---- modules/web/site/slot/README.md | 45 ++++-- modules/web/site/slot/main.bicep | 25 +-- modules/web/site/slot/main.json | 47 ++++-- .../static-site/.test/common/main.test.bicep | 8 +- modules/web/static-site/README.md | 71 ++++---- modules/web/static-site/main.bicep | 25 +-- modules/web/static-site/main.json | 47 ++++-- 217 files changed, 4835 insertions(+), 2897 deletions(-) delete mode 100644 modules/app-configuration/configuration-store/key-value/.bicep/nested_roleAssignments.bicep diff --git a/modules/api-management/service/.test/common/main.test.bicep b/modules/api-management/service/.test/common/main.test.bicep index fbed3af64f..b2435a08bf 100644 --- a/modules/api-management/service/.test/common/main.test.bicep +++ b/modules/api-management/service/.test/common/main.test.bicep @@ -82,6 +82,9 @@ module testDeployment '../../main.bicep' = { } } ] + managedIdentities: { + systemAssigned: true + } roleAssignments: [ { roleDefinitionIdOrName: 'Reader' diff --git a/modules/api-management/service/.test/max/main.test.bicep b/modules/api-management/service/.test/max/main.test.bicep index e2902a543c..4311cd5ebb 100644 --- a/modules/api-management/service/.test/max/main.test.bicep +++ b/modules/api-management/service/.test/max/main.test.bicep @@ -201,9 +201,11 @@ module testDeployment '../../main.bicep' = { scope: '/apis' } ] - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/api-management/service/README.md b/modules/api-management/service/README.md index 81826b9b9c..8a7569241b 100644 --- a/modules/api-management/service/README.md +++ b/modules/api-management/service/README.md @@ -69,6 +69,9 @@ module service 'br:bicep/modules/api-management.service:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + } policies: [ { format: 'xml' @@ -141,6 +144,11 @@ module service 'br:bicep/modules/api-management.service:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, "policies": { "value": [ { @@ -279,6 +287,12 @@ module service 'br:bicep/modules/api-management.service:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } namedValues: [ { displayName: 'apimkey' @@ -339,15 +353,11 @@ module service 'br:bicep/modules/api-management.service:1.0.0' = { name: 'testArmSubscriptionAllApis' } ] - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -463,6 +473,14 @@ module service 'br:bicep/modules/api-management.service:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "namedValues": { "value": [ { @@ -535,20 +553,12 @@ module service 'br:bicep/modules/api-management.service:1.0.0' = { } ] }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -644,6 +654,7 @@ module service 'br:bicep/modules/api-management.service:1.0.0' = { | [`identityProviders`](#parameter-identityproviders) | array | Identity providers. | | [`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. | | [`minApiVersion`](#parameter-minapiversion) | string | Limit control plane API calls to API Management service with version equal to or newer than this value. | | [`namedValues`](#parameter-namedvalues) | array | Named values. | | [`newGuidValue`](#parameter-newguidvalue) | string | Necessary to create a new GUID. | @@ -657,9 +668,7 @@ module service 'br:bicep/modules/api-management.service:1.0.0' = { | [`skuCount`](#parameter-skucount) | int | The instance size of this API Management service. | | [`subnetResourceId`](#parameter-subnetresourceid) | string | The full resource ID of a subnet in a virtual network to deploy the API Management service in. | | [`subscriptions`](#parameter-subscriptions) | array | Subscriptions. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`virtualNetworkType`](#parameter-virtualnetworktype) | string | The type of VPN in which API Management service needs to be configured in. None (Default Value) means the API Management service is not part of any Virtual Network, External means the API Management deployment is set up inside a Virtual Network having an internet Facing Endpoint, and Internal means that API Management deployment is setup inside a Virtual Network having an Intranet Facing Endpoint only. | | [`zones`](#parameter-zones) | array | A list of availability zones denoting where the resource needs to come from. | @@ -903,6 +912,32 @@ 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: `minApiVersion` Limit control plane API calls to API Management service with version equal to or newer than this value. @@ -1075,13 +1110,6 @@ Subscriptions. - Type: array - Default: `[]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -1089,13 +1117,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `virtualNetworkType` The type of VPN in which API Management service needs to be configured in. None (Default Value) means the API Management service is not part of any Virtual Network, External means the API Management deployment is set up inside a Virtual Network having an internet Facing Endpoint, and Internal means that API Management deployment is setup inside a Virtual Network having an Intranet Facing Endpoint only. @@ -1120,7 +1141,7 @@ A list of availability zones denoting where the resource needs to come from. | `name` | string | The name of the API management service. | | `resourceGroupName` | string | The resource group the API management service was deployed into. | | `resourceId` | string | The resource ID of the API management service. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/api-management/service/main.bicep b/modules/api-management/service/main.bicep index 2b28c3d8b1..9d7119f4b8 100644 --- a/modules/api-management/service/main.bicep +++ b/modules/api-management/service/main.bicep @@ -27,11 +27,8 @@ param enableClientCertificate bool = false @description('Optional. Custom hostname configuration of the API Management service.') param hostnameConfigurations array = [] -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. Location for all Resources.') param location string = resourceGroup().location @@ -135,11 +132,11 @@ var enableReferencedModulesTelemetry = false var authorizationServerList = !empty(authorizationServers) ? authorizationServers.secureList : [] -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 = { @@ -454,7 +451,7 @@ output resourceId string = service.id output resourceGroupName string = resourceGroup().name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(service.identity, 'principalId') ? service.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(service.identity, 'principalId') ? service.identity.principalId : '' @description('The location the resource was deployed into.') output location string = service.location @@ -463,6 +460,14 @@ output location string = service.location // 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? diff --git a/modules/api-management/service/main.json b/modules/api-management/service/main.json index 7122d8c63c..53e81dd1bd 100644 --- a/modules/api-management/service/main.json +++ b/modules/api-management/service/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "5480824753048175780" + "templateHash": "3274387832095626640" }, "name": "API Management Services", "description": "This module deploys an API Management Service.", "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": { @@ -268,18 +291,10 @@ "description": "Optional. Custom hostname configuration of the API Management service." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "location": { @@ -486,8 +501,8 @@ "variables": { "enableReferencedModulesTelemetry": false, "authorizationServerList": "[if(not(empty(parameters('authorizationServers'))), parameters('authorizationServers').secureList, createArray())]", - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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": { "API Management Developer Portal Content Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c031e6a8-4391-4de0-8d69-4706a7ed3729')]", "API Management Service Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '312a565d-c81f-4fd8-895a-4e21e48d571c')]", @@ -3053,12 +3068,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('service', '2021-08-01', 'full').identity, 'principalId')), reference('service', '2021-08-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('service', '2021-08-01', 'full').identity, 'principalId')), reference('service', '2021-08-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/app-configuration/configuration-store/.test/common/main.test.bicep b/modules/app-configuration/configuration-store/.test/common/main.test.bicep index fca8a214b8..53df736af2 100644 --- a/modules/app-configuration/configuration-store/.test/common/main.test.bicep +++ b/modules/app-configuration/configuration-store/.test/common/main.test.bicep @@ -109,9 +109,11 @@ module testDeployment '../../main.bicep' = { } ] softDeleteRetentionInDays: 1 - systemAssignedIdentity: false - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/app-configuration/configuration-store/.test/encr/main.test.bicep b/modules/app-configuration/configuration-store/.test/encr/main.test.bicep index 28c092fff8..51e9ff0202 100644 --- a/modules/app-configuration/configuration-store/.test/encr/main.test.bicep +++ b/modules/app-configuration/configuration-store/.test/encr/main.test.bicep @@ -80,8 +80,10 @@ module testDeployment '../../main.bicep' = { } ] softDeleteRetentionInDays: 1 - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/app-configuration/configuration-store/README.md b/modules/app-configuration/configuration-store/README.md index 15a5ab72fc..7e4babb679 100644 --- a/modules/app-configuration/configuration-store/README.md +++ b/modules/app-configuration/configuration-store/README.md @@ -87,6 +87,12 @@ module configurationStore 'br:bicep/modules/app-configuration.configuration-stor kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } roleAssignments: [ { principalId: '' @@ -95,15 +101,11 @@ module configurationStore 'br:bicep/modules/app-configuration.configuration-stor } ] softDeleteRetentionInDays: 1 - systemAssignedIdentity: false tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -175,6 +177,14 @@ module configurationStore 'br:bicep/modules/app-configuration.configuration-stor "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "roleAssignments": { "value": [ { @@ -187,20 +197,12 @@ module configurationStore 'br:bicep/modules/app-configuration.configuration-stor "softDeleteRetentionInDays": { "value": 1 }, - "systemAssignedIdentity": { - "value": false - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -243,6 +245,11 @@ module configurationStore 'br:bicep/modules/app-configuration.configuration-stor value: 'valueName' } ] + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } roleAssignments: [ { principalId: '' @@ -256,9 +263,6 @@ module configurationStore 'br:bicep/modules/app-configuration.configuration-stor 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -317,6 +321,13 @@ module configurationStore 'br:bicep/modules/app-configuration.configuration-stor } ] }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "roleAssignments": { "value": [ { @@ -335,11 +346,6 @@ module configurationStore 'br:bicep/modules/app-configuration.configuration-stor "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -527,14 +533,13 @@ module configurationStore 'br:bicep/modules/app-configuration.configuration-stor | [`keyValues`](#parameter-keyvalues) | array | All Key / Values to create. Requires local authentication to be 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. | | [`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'. | | [`sku`](#parameter-sku) | string | Pricing tier of App Configuration. | | [`softDeleteRetentionInDays`](#parameter-softdeleteretentionindays) | int | The amount of time in days that the configuration store will be retained when it is soft deleted. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | ### Parameter: `cMKKeyName` @@ -749,6 +754,32 @@ 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` Name of the Azure App Configuration. @@ -1014,13 +1045,6 @@ The amount of time in days that the configuration store will be retained when it - Type: int - Default: `1` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -1028,13 +1052,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs @@ -1044,7 +1061,7 @@ The ID(s) to assign to the resource. | `name` | string | The name of the app configuration. | | `resourceGroupName` | string | The resource group the app configuration store was deployed into. | | `resourceId` | string | The resource ID of the app configuration. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/app-configuration/configuration-store/key-value/.bicep/nested_roleAssignments.bicep b/modules/app-configuration/configuration-store/key-value/.bicep/nested_roleAssignments.bicep deleted file mode 100644 index 2b0b5813ba..0000000000 --- a/modules/app-configuration/configuration-store/key-value/.bicep/nested_roleAssignments.bicep +++ /dev/null @@ -1,70 +0,0 @@ -@sys.description('Required. The IDs of the principals to assign the role to.') -param principalIds array - -@sys.description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') -param roleDefinitionIdOrName string - -@sys.description('Required. The resource ID of the resource to apply the role assignment to.') -param resourceId string - -@sys.description('Optional. The principal type of the assigned principal ID.') -@allowed([ - 'ServicePrincipal' - 'Group' - 'User' - 'ForeignGroup' - 'Device' - '' -]) -param principalType string = '' - -@sys.description('Optional. The description of the role assignment.') -param description string = '' - -@sys.description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container".') -param condition string = '' - -@sys.description('Optional. Version of the condition.') -@allowed([ - '2.0' -]) -param conditionVersion string = '2.0' - -@sys.description('Optional. Id of the delegated managed identity resource.') -param delegatedManagedIdentityResourceId string = '' - -var builtInRoleNames = { - 'App Configuration Data Owner': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b') - 'App Configuration Data Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071') - Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') - 'Log Analytics Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293') - 'Log Analytics Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893') - 'Managed Application Contributor Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '641177b8-a67a-45b9-a033-47bc880bb21e') - 'Managed Application Operator Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c7393b34-138c-406f-901b-d8cf2b17e6ae') - 'Managed Applications Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b9331d33-8a36-4f8c-b097-4f54124fdb44') - 'Monitoring Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa') - 'Monitoring Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05') - Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') - Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') - 'Resource Policy Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '36243c78-bf99-498c-9df9-86d9f8d28608') - 'Role Based Access Control Administrator (Preview)': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168') - 'User Access Administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9') -} - -resource appConfiguration 'Microsoft.AppConfiguration/configurationStores@2023-03-01' existing = { - name: last(split(resourceId, '/'))! -} - -resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for principalId in principalIds: { - name: guid(appConfiguration.id, principalId, roleDefinitionIdOrName) - properties: { - description: description - roleDefinitionId: contains(builtInRoleNames, roleDefinitionIdOrName) ? builtInRoleNames[roleDefinitionIdOrName] : roleDefinitionIdOrName - principalId: principalId - principalType: !empty(principalType) ? any(principalType) : null - condition: !empty(condition) ? condition : null - conditionVersion: !empty(conditionVersion) && !empty(condition) ? conditionVersion : null - delegatedManagedIdentityResourceId: !empty(delegatedManagedIdentityResourceId) ? delegatedManagedIdentityResourceId : null - } - scope: appConfiguration -}] diff --git a/modules/app-configuration/configuration-store/main.bicep b/modules/app-configuration/configuration-store/main.bicep index e3c46d215d..605a827075 100644 --- a/modules/app-configuration/configuration-store/main.bicep +++ b/modules/app-configuration/configuration-store/main.bicep @@ -8,11 +8,8 @@ param name string @description('Optional. Location for all Resources.') param location string = resourceGroup().location -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @allowed([ 'Free' @@ -82,12 +79,12 @@ param privateEndpoints privateEndpointType var enableReferencedModulesTelemetry = false -var identityType = systemAssignedIdentity ? 'SystemAssigned' : !empty(userAssignedIdentities) ? 'UserAssigned' : 'None' +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 = { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null -} +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 = { 'App Compliance Automation Administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2') @@ -245,7 +242,7 @@ output resourceId string = configurationStore.id output resourceGroupName string = resourceGroup().name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(configurationStore.identity, 'principalId') ? configurationStore.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(configurationStore.identity, 'principalId') ? configurationStore.identity.principalId : '' @description('The location the resource was deployed into.') output location string = configurationStore.location @@ -254,6 +251,14 @@ output location string = configurationStore.location // 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? diff --git a/modules/app-configuration/configuration-store/main.json b/modules/app-configuration/configuration-store/main.json index f0132feeea..e5b8f23942 100644 --- a/modules/app-configuration/configuration-store/main.json +++ b/modules/app-configuration/configuration-store/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "1654739294339670098" + "templateHash": "5839345851698938345" }, "name": "App Configuration Stores", "description": "This module deploys an App Configuration Store.", "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": { @@ -374,18 +397,10 @@ "description": "Optional. Location for all Resources." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "sku": { @@ -521,11 +536,8 @@ }, "variables": { "enableReferencedModulesTelemetry": false, - "identityType": "[if(parameters('systemAssignedIdentity'), 'SystemAssigned', if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": { - "type": "[variables('identityType')]", - "userAssignedIdentities": "[if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), 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(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": { "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", @@ -1377,12 +1389,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('configurationStore', '2023-03-01', 'full').identity, 'principalId')), reference('configurationStore', '2023-03-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('configurationStore', '2023-03-01', 'full').identity, 'principalId')), reference('configurationStore', '2023-03-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/app/container-app/.test/common/main.test.bicep b/modules/app/container-app/.test/common/main.test.bicep index 19585fed16..70db0d5eef 100644 --- a/modules/app/container-app/.test/common/main.test.bicep +++ b/modules/app/container-app/.test/common/main.test.bicep @@ -64,8 +64,10 @@ module testDeployment '../../main.bicep' = { kind: 'CanNotDelete' name: 'myCustomLockName' } - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } secrets: { secureList: [ diff --git a/modules/app/container-app/README.md b/modules/app/container-app/README.md index dd5a6c3f12..4da6b25062 100644 --- a/modules/app/container-app/README.md +++ b/modules/app/container-app/README.md @@ -79,6 +79,11 @@ module containerApp 'br:bicep/modules/app.container-app:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } secrets: { secureList: [ { @@ -91,9 +96,6 @@ module containerApp 'br:bicep/modules/app.container-app:1.0.0' = { Env: 'test' 'hidden-title': 'This is visible in the resource name' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -159,6 +161,13 @@ module containerApp 'br:bicep/modules/app.container-app:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "secrets": { "value": { "secureList": [ @@ -174,11 +183,6 @@ module containerApp 'br:bicep/modules/app.container-app:1.0.0' = { "Env": "test", "hidden-title": "This is visible in the resource name" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -303,6 +307,7 @@ module containerApp 'br:bicep/modules/app.container-app:1.0.0' = { | [`ipSecurityRestrictions`](#parameter-ipsecurityrestrictions) | array | Rules to restrict incoming IP address. | | [`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. | | [`maxInactiveRevisions`](#parameter-maxinactiverevisions) | int | Max inactive revisions a Container App can have. | | [`registries`](#parameter-registries) | array | Collection of private container registry credentials for containers used by the Container app. | | [`revisionSuffix`](#parameter-revisionsuffix) | string | User friendly suffix that is appended to the revision name. | @@ -311,13 +316,11 @@ module containerApp 'br:bicep/modules/app.container-app:1.0.0' = { | [`scaleMinReplicas`](#parameter-scaleminreplicas) | int | Minimum number of container replicas. | | [`scaleRules`](#parameter-scalerules) | array | Scaling rules. | | [`secrets`](#parameter-secrets) | secureObject | The secrets of the Container App. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`trafficLabel`](#parameter-trafficlabel) | string | Associates a traffic label with a revision. Label name should be consist of lower case alphanumeric characters or dashes. | | [`trafficLatestRevision`](#parameter-trafficlatestrevision) | bool | Indicates that the traffic weight belongs to a latest stable revision. | | [`trafficRevisionName`](#parameter-trafficrevisionname) | string | Name of a revision. | | [`trafficWeight`](#parameter-trafficweight) | int | Traffic weight assigned to a revision. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The set of user assigned identities associated with the resource, the userAssignedIdentities dictionary keys will be ARM resource IDs and The dictionary values can be empty objects ({}) in requests. | | [`volumes`](#parameter-volumes) | array | List of volume definitions for the Container App. | | [`workloadProfileType`](#parameter-workloadprofiletype) | string | Workload profile type to pin for container app execution. | @@ -446,6 +449,32 @@ 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: `maxInactiveRevisions` Max inactive revisions a Container App can have. @@ -569,13 +598,6 @@ The secrets of the Container App. - Type: secureObject - Default: `{object}` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -611,13 +633,6 @@ Traffic weight assigned to a revision. - Type: int - Default: `100` -### Parameter: `userAssignedIdentities` - -The set of user assigned identities associated with the resource, the userAssignedIdentities dictionary keys will be ARM resource IDs and The dictionary values can be empty objects ({}) in requests. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `volumes` List of volume definitions for the Container App. @@ -641,6 +656,7 @@ Workload profile type to pin for container app execution. | `name` | string | The name of the Container App. | | `resourceGroupName` | string | The name of the resource group the Container App was deployed into. | | `resourceId` | string | The resource ID of the Container App. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/app/container-app/main.bicep b/modules/app/container-app/main.bicep index cb4df29cfa..6203e95475 100644 --- a/modules/app/container-app/main.bicep +++ b/modules/app/container-app/main.bicep @@ -54,11 +54,8 @@ param tags object = {} @description('Optional. Collection of private container registry credentials for containers used by the Container app.') param registries array = [] -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The set of user assigned identities associated with the resource, the userAssignedIdentities dictionary keys will be ARM resource IDs and The dictionary values can be empty objects ({}) in requests.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @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.') param roleAssignments roleAssignmentType @@ -114,11 +111,11 @@ param workloadProfileType string = '' var secretList = !empty(secrets) ? secrets.secureList : [] -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 = { @@ -220,6 +217,9 @@ output resourceGroupName string = resourceGroup().name @description('The name of the Container App.') output name string = containerApp.name +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(containerApp.identity, 'principalId') ? containerApp.identity.principalId : '' + @description('The location the resource was deployed into.') output location string = containerApp.location @@ -227,6 +227,14 @@ output location string = containerApp.location // 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? diff --git a/modules/app/container-app/main.json b/modules/app/container-app/main.json index 904218dfda..ee8c7769c7 100644 --- a/modules/app/container-app/main.json +++ b/modules/app/container-app/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "15975254087801616307" + "templateHash": "18263232031845288996" }, "name": "Container Apps", "description": "This module deploys a Container App.", "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": { @@ -211,18 +234,10 @@ "description": "Optional. Collection of private container registry credentials for containers used by the Container app." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The set of user assigned identities associated with the resource, the userAssignedIdentities dictionary keys will be ARM resource IDs and The dictionary values can be empty objects ({}) in requests." + "description": "Optional. The managed identity definition for this resource." } }, "roleAssignments": { @@ -345,8 +360,8 @@ }, "variables": { "secretList": "[if(not(empty(parameters('secrets'))), parameters('secrets').secureList, createArray())]", - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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": { "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", @@ -477,6 +492,13 @@ }, "value": "[parameters('name')]" }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('containerApp', '2022-10-01', 'full').identity, 'principalId')), reference('containerApp', '2022-10-01', 'full').identity.principalId, '')]" + }, "location": { "type": "string", "metadata": { diff --git a/modules/automation/automation-account/.test/common/main.test.bicep b/modules/automation/automation-account/.test/common/main.test.bicep index c47be89759..38861ec093 100644 --- a/modules/automation/automation-account/.test/common/main.test.bicep +++ b/modules/automation/automation-account/.test/common/main.test.bicep @@ -218,9 +218,11 @@ module testDeployment '../../main.bicep' = { ] } ] - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } variables: [ { diff --git a/modules/automation/automation-account/.test/encr/main.test.bicep b/modules/automation/automation-account/.test/encr/main.test.bicep index 8fa4abaa5d..389ca3eae8 100644 --- a/modules/automation/automation-account/.test/encr/main.test.bicep +++ b/modules/automation/automation-account/.test/encr/main.test.bicep @@ -57,8 +57,10 @@ module testDeployment '../../main.bicep' = { cMKKeyName: nestedDependencies.outputs.keyVaultEncryptionKeyName cMKKeyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId cMKUserAssignedIdentityResourceId: nestedDependencies.outputs.managedIdentityResourceId - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } } } diff --git a/modules/automation/automation-account/README.md b/modules/automation/automation-account/README.md index b832c2ad0c..de8dee9816 100644 --- a/modules/automation/automation-account/README.md +++ b/modules/automation/automation-account/README.md @@ -91,6 +91,12 @@ module automationAccount 'br:bicep/modules/automation.automation-account:1.0.0' kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } modules: [ { name: 'PSWindowsUpdate' @@ -208,15 +214,11 @@ module automationAccount 'br:bicep/modules/automation.automation-account:1.0.0' ] } ] - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } variables: [ { description: 'TestStringDescription' @@ -314,6 +316,14 @@ module automationAccount 'br:bicep/modules/automation.automation-account:1.0.0' "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "modules": { "value": [ { @@ -443,9 +453,6 @@ module automationAccount 'br:bicep/modules/automation.automation-account:1.0.0' } ] }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", @@ -453,11 +460,6 @@ module automationAccount 'br:bicep/modules/automation.automation-account:1.0.0' "Role": "DeploymentValidation" } }, - "userAssignedIdentities": { - "value": { - "": {} - } - }, "variables": { "value": [ { @@ -512,8 +514,10 @@ module automationAccount 'br:bicep/modules/automation.automation-account:1.0.0' cMKKeyVaultResourceId: '' cMKUserAssignedIdentityResourceId: '' enableDefaultTelemetry: '' - userAssignedIdentities: { - '': {} + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] } } } @@ -548,9 +552,11 @@ module automationAccount 'br:bicep/modules/automation.automation-account:1.0.0' "enableDefaultTelemetry": { "value": "" }, - "userAssignedIdentities": { + "managedIdentities": { "value": { - "": {} + "userAssignedResourcesIds": [ + "" + ] } } } @@ -638,6 +644,7 @@ module automationAccount 'br:bicep/modules/automation.automation-account:1.0.0' | [`linkedWorkspaceResourceId`](#parameter-linkedworkspaceresourceid) | string | ID of the log analytics workspace to be linked to the deployed automation account. | | [`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. | | [`modules`](#parameter-modules) | array | List of modules to be created in the automation account. | | [`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. | @@ -646,9 +653,7 @@ module automationAccount 'br:bicep/modules/automation.automation-account:1.0.0' | [`schedules`](#parameter-schedules) | array | List of schedules to be created in the automation account. | | [`skuName`](#parameter-skuname) | string | SKU name of the account. | | [`softwareUpdateConfigurations`](#parameter-softwareupdateconfigurations) | array | List of softwareUpdateConfigurations to be created in the automation account. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the Automation Account resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`variables`](#parameter-variables) | array | List of variables to be created in the automation account. | ### Parameter: `cMKKeyName` @@ -863,6 +868,32 @@ 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: `modules` List of modules to be created in the automation account. @@ -1149,13 +1180,6 @@ List of softwareUpdateConfigurations to be created in the automation account. - Type: array - Default: `[]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the Automation Account resource. @@ -1163,13 +1187,6 @@ Tags of the Automation Account resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `variables` List of variables to be created in the automation account. @@ -1186,7 +1203,7 @@ List of variables to be created in the automation account. | `name` | string | The name of the deployed automation account. | | `resourceGroupName` | string | The resource group of the deployed automation account. | | `resourceId` | string | The resource ID of the deployed automation account. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/automation/automation-account/main.bicep b/modules/automation/automation-account/main.bicep index b921f002e8..908b6b3811 100644 --- a/modules/automation/automation-account/main.bicep +++ b/modules/automation/automation-account/main.bicep @@ -68,11 +68,8 @@ param privateEndpoints privateEndpointType @description('Optional. The diagnostic settings of the service.') param diagnosticSettings diagnosticSettingType -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. The lock settings of the service.') param lock lockType @@ -88,11 +85,11 @@ param enableDefaultTelemetry bool = true var enableReferencedModulesTelemetry = false -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 = { @@ -387,7 +384,7 @@ output resourceId string = automationAccount.id output resourceGroupName string = resourceGroup().name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(automationAccount.identity, 'principalId') ? automationAccount.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(automationAccount.identity, 'principalId') ? automationAccount.identity.principalId : '' @description('The location the resource was deployed into.') output location string = automationAccount.location @@ -396,6 +393,14 @@ output location string = automationAccount.location // 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? diff --git a/modules/automation/automation-account/main.json b/modules/automation/automation-account/main.json index 4c84eda080..f6484661e3 100644 --- a/modules/automation/automation-account/main.json +++ b/modules/automation/automation-account/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "13507604496073736605" + "templateHash": "5962075210200629853" }, "name": "Automation Accounts", "description": "This module deploys an Azure Automation Account.", "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": { @@ -499,18 +522,10 @@ "description": "Optional. The diagnostic settings of the service." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "lock": { @@ -542,8 +557,8 @@ }, "variables": { "enableReferencedModulesTelemetry": false, - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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": { "Automation Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f353d9bd-d4a6-484e-a77a-8050b599b867')]", "Automation Job Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4fe576fe-1146-4730-92eb-48519fa6bf9f')]", @@ -2888,12 +2903,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('automationAccount', '2022-08-08', 'full').identity, 'principalId')), reference('automationAccount', '2022-08-08', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('automationAccount', '2022-08-08', 'full').identity, 'principalId')), reference('automationAccount', '2022-08-08', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/batch/batch-account/.test/common/main.test.bicep b/modules/batch/batch-account/.test/common/main.test.bicep index f41129e7f6..8187f404f6 100644 --- a/modules/batch/batch-account/.test/common/main.test.bicep +++ b/modules/batch/batch-account/.test/common/main.test.bicep @@ -117,7 +117,9 @@ module testDeployment '../../main.bicep' = { ] storageAccessIdentity: nestedDependencies.outputs.managedIdentityResourceId storageAuthenticationMode: 'BatchAccountManagedIdentity' - systemAssignedIdentity: true + managedIdentities: { + systemAssigned: true + } tags: { 'hidden-title': 'This is visible in the resource name' Environment: 'Non-Prod' diff --git a/modules/batch/batch-account/.test/encr/main.test.bicep b/modules/batch/batch-account/.test/encr/main.test.bicep index 19c638ffcc..c3ae0ef1cc 100644 --- a/modules/batch/batch-account/.test/encr/main.test.bicep +++ b/modules/batch/batch-account/.test/encr/main.test.bicep @@ -76,8 +76,10 @@ module testDeployment '../../main.bicep' = { ] storageAccessIdentity: nestedDependencies.outputs.managedIdentityResourceId storageAuthenticationMode: 'BatchAccountManagedIdentity' - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/batch/batch-account/README.md b/modules/batch/batch-account/README.md index 66ec1ea280..0669214e97 100644 --- a/modules/batch/batch-account/README.md +++ b/modules/batch/batch-account/README.md @@ -71,6 +71,9 @@ module batchAccount 'br:bicep/modules/batch.batch-account:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + } poolAllocationMode: 'BatchService' privateEndpoints: [ { @@ -101,7 +104,6 @@ module batchAccount 'br:bicep/modules/batch.batch-account:1.0.0' = { ] storageAccessIdentity: '' storageAuthenticationMode: 'BatchAccountManagedIdentity' - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -156,6 +158,11 @@ module batchAccount 'br:bicep/modules/batch.batch-account:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, "poolAllocationMode": { "value": "BatchService" }, @@ -196,9 +203,6 @@ module batchAccount 'br:bicep/modules/batch.batch-account:1.0.0' = { "storageAuthenticationMode": { "value": "BatchAccountManagedIdentity" }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", @@ -230,6 +234,11 @@ module batchAccount 'br:bicep/modules/batch.batch-account:1.0.0' = { cMKKeyName: '' cMKKeyVaultResourceId: '' enableDefaultTelemetry: '' + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } poolAllocationMode: 'BatchService' privateEndpoints: [ { @@ -252,9 +261,6 @@ module batchAccount 'br:bicep/modules/batch.batch-account:1.0.0' = { 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -288,6 +294,13 @@ module batchAccount 'br:bicep/modules/batch.batch-account:1.0.0' = { "enableDefaultTelemetry": { "value": "" }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "poolAllocationMode": { "value": "BatchService" }, @@ -319,11 +332,6 @@ module batchAccount 'br:bicep/modules/batch.batch-account:1.0.0' = { "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -412,6 +420,7 @@ module batchAccount 'br:bicep/modules/batch.batch-account:1.0.0' = { | [`enableDefaultTelemetry`](#parameter-enabledefaulttelemetry) | bool | Enable telemetry via a Globally Unique Identifier (GUID). | | [`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. | | [`networkProfileAllowedIpRanges`](#parameter-networkprofileallowedipranges) | array | Array of IP ranges to filter client IP address. It is only applicable when publicNetworkAccess is not explicitly disabled. | | [`networkProfileDefaultAction`](#parameter-networkprofiledefaultaction) | string | The network profile default action for endpoint access. It is only applicable when publicNetworkAccess is not explicitly disabled. | | [`poolAllocationMode`](#parameter-poolallocationmode) | string | The allocation mode for creating pools in the Batch account. Determines which quota will be used. | @@ -420,9 +429,7 @@ module batchAccount 'br:bicep/modules/batch.batch-account:1.0.0' = { | [`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'. | | [`storageAccessIdentity`](#parameter-storageaccessidentity) | 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. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | ### Parameter: `allowedAuthenticationModes` @@ -616,6 +623,32 @@ Optional. Specify the name of lock. - Required: No - Type: string +### Parameter: `managedIdentities` + +The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both. +- 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` Name of the Azure Batch. @@ -910,13 +943,6 @@ The authentication mode which the Batch service will use to manage the auto-stor - Default: `'StorageKeys'` - Allowed: `[BatchAccountManagedIdentity, StorageKeys]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -924,13 +950,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs @@ -940,6 +959,7 @@ The ID(s) to assign to the resource. | `name` | string | The name of the batch account. | | `resourceGroupName` | string | The resource group the batch account was deployed into. | | `resourceId` | string | The resource ID of the batch account. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/batch/batch-account/main.bicep b/modules/batch/batch-account/main.bicep index e0ca3aaf85..4c322f5d36 100644 --- a/modules/batch/batch-account/main.bicep +++ b/modules/batch/batch-account/main.bicep @@ -8,11 +8,8 @@ param name string @description('Optional. Location for all Resources.') param location string = resourceGroup().location -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both.') +param managedIdentities managedIdentitiesType @description('Required. The resource ID of the storage account to be used for auto-storage account.') param storageAccountId string @@ -90,12 +87,12 @@ param cMKKeyVersion string = '' @description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') param enableDefaultTelemetry bool = true -var identityType = systemAssignedIdentity ? 'SystemAssigned' : !empty(userAssignedIdentities) ? 'UserAssigned' : 'None' +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 = { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null -} +var identity = !empty(managedIdentities) ? { + type: (managedIdentities.?systemAssigned ?? false) ? 'SystemAssigned' : (!empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null) + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null +} : null var networkProfileIpRules = [for networkProfileAllowedIpRange in networkProfileAllowedIpRanges: { action: 'Allow' @@ -257,10 +254,21 @@ output resourceGroupName string = resourceGroup().name @description('The location the resource was deployed into.') output location string = batchAccount.location +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(batchAccount.identity, 'principalId') ? batchAccount.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? diff --git a/modules/batch/batch-account/main.json b/modules/batch/batch-account/main.json index a44629002b..704866f515 100644 --- a/modules/batch/batch-account/main.json +++ b/modules/batch/batch-account/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "15411894480472906103" + "templateHash": "8921010374521375351" }, "name": "Batch Accounts", "description": "This module deploys a Batch Account.", "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": { @@ -374,18 +397,10 @@ "description": "Optional. Location for all Resources." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." } }, "storageAccountId": { @@ -543,11 +558,8 @@ } } ], - "identityType": "[if(parameters('systemAssignedIdentity'), 'SystemAssigned', if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": { - "type": "[variables('identityType')]", - "userAssignedIdentities": "[if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), 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(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "nodeIdentityReference": "[if(not(empty(parameters('storageAccessIdentity'))), createObject('resourceId', if(not(empty(parameters('storageAccessIdentity'))), parameters('storageAccessIdentity'), null())), null())]", "autoStorageConfig": { "authenticationMode": "[parameters('storageAuthenticationMode')]", @@ -1258,6 +1270,13 @@ "description": "The location the resource was deployed into." }, "value": "[reference('batchAccount', '2022-06-01', '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('batchAccount', '2022-06-01', 'full').identity, 'principalId')), reference('batchAccount', '2022-06-01', 'full').identity.principalId, '')]" } } } \ No newline at end of file diff --git a/modules/cache/redis/.test/common/dependencies.bicep b/modules/cache/redis/.test/common/dependencies.bicep index bbf0956900..8218e0c1ad 100644 --- a/modules/cache/redis/.test/common/dependencies.bicep +++ b/modules/cache/redis/.test/common/dependencies.bicep @@ -1,6 +1,9 @@ @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 @@ -42,6 +45,14 @@ 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 Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + @description('The resource ID of the created Virtual Network Subnet.') output subnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/modules/cache/redis/.test/common/main.test.bicep b/modules/cache/redis/.test/common/main.test.bicep index ccc1f3f939..eba4aadbe5 100644 --- a/modules/cache/redis/.test/common/main.test.bicep +++ b/modules/cache/redis/.test/common/main.test.bicep @@ -38,6 +38,7 @@ module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup name: '${uniqueString(deployment().name, location)}-nestedDependencies' params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' } } @@ -106,7 +107,12 @@ module testDeployment '../../main.bicep' = { redisVersion: '6' shardCount: 1 skuName: 'Premium' - systemAssignedIdentity: true + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } tags: { 'hidden-title': 'This is visible in the resource name' resourceType: 'Redis Cache' diff --git a/modules/cache/redis/README.md b/modules/cache/redis/README.md index 16249d853e..580ce90db2 100644 --- a/modules/cache/redis/README.md +++ b/modules/cache/redis/README.md @@ -70,6 +70,12 @@ module redis 'br:bicep/modules/cache.redis:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } minimumTlsVersion: '1.2' privateEndpoints: [ { @@ -88,7 +94,6 @@ module redis 'br:bicep/modules/cache.redis:1.0.0' = { redisVersion: '6' shardCount: 1 skuName: 'Premium' - systemAssignedIdentity: true tags: { 'hidden-title': 'This is visible in the resource name' resourceType: 'Redis Cache' @@ -150,6 +155,14 @@ module redis 'br:bicep/modules/cache.redis:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "minimumTlsVersion": { "value": "1.2" }, @@ -180,9 +193,6 @@ module redis 'br:bicep/modules/cache.redis:1.0.0' = { "skuName": { "value": "Premium" }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "hidden-title": "This is visible in the resource name", @@ -272,6 +282,7 @@ module redis 'br:bicep/modules/cache.redis:1.0.0' = { | [`enableNonSslPort`](#parameter-enablenonsslport) | bool | Specifies whether the non-ssl Redis server port (6379) is enabled. | | [`location`](#parameter-location) | string | The location to deploy the Redis cache service. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | | [`minimumTlsVersion`](#parameter-minimumtlsversion) | string | Requires clients to use a specified TLS version (or higher) to connect. | | [`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. | @@ -284,10 +295,8 @@ module redis 'br:bicep/modules/cache.redis:1.0.0' = { | [`skuName`](#parameter-skuname) | string | The type of Redis cache to deploy. | | [`staticIP`](#parameter-staticip) | string | Static IP address. Optionally, may be specified when deploying a Redis cache inside an existing Azure Virtual Network; auto assigned by default. | | [`subnetId`](#parameter-subnetid) | string | The full resource ID of a subnet in a virtual network to deploy the Redis cache in. Example format: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/Microsoft.{Network|ClassicNetwork}/VirtualNetworks/vnet1/subnets/subnet1. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`tenantSettings`](#parameter-tenantsettings) | object | A dictionary of tenant settings. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`zoneRedundant`](#parameter-zoneredundant) | bool | When true, replicas will be provisioned in availability zones specified in the zones parameter. | | [`zones`](#parameter-zones) | array | If the zoneRedundant parameter is true, replicas will be provisioned in the availability zones specified here. Otherwise, the service will choose where replicas are deployed. | @@ -462,6 +471,32 @@ 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: `minimumTlsVersion` Requires clients to use a specified TLS version (or higher) to connect. @@ -778,13 +813,6 @@ The full resource ID of a subnet in a virtual network to deploy the Redis cache - Type: string - Default: `''` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -799,13 +827,6 @@ A dictionary of tenant settings. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `zoneRedundant` When true, replicas will be provisioned in availability zones specified in the zones parameter. @@ -832,6 +853,7 @@ If the zoneRedundant parameter is true, replicas will be provisioned in the avai | `resourceId` | string | The resource ID of the Redis Cache. | | `sslPort` | int | Redis SSL port. | | `subnetId` | string | The full resource ID of a subnet in a virtual network where the Redis Cache was deployed in. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/cache/redis/main.bicep b/modules/cache/redis/main.bicep index 6794af2ed2..f35bce1160 100644 --- a/modules/cache/redis/main.bicep +++ b/modules/cache/redis/main.bicep @@ -17,11 +17,8 @@ param roleAssignments roleAssignmentType @description('Optional. Tags of the resource.') param tags object = {} -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. Specifies whether the non-ssl Redis server port (6379) is enabled.') param enableNonSslPort bool = false @@ -110,12 +107,12 @@ param enableDefaultTelemetry bool = true var availabilityZones = skuName == 'Premium' ? zoneRedundant ? !empty(zones) ? zones : pickZones('Microsoft.Cache', 'redis', location, 3) : [] : [] -var identityType = systemAssignedIdentity ? 'SystemAssigned' : !empty(userAssignedIdentities) ? 'UserAssigned' : 'None' +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 = { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null -} +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 enableReferencedModulesTelemetry = false @@ -257,6 +254,9 @@ output sslPort int = redis.properties.sslPort @description('The full resource ID of a subnet in a virtual network where the Redis Cache was deployed in.') output subnetId string = !empty(subnetId) ? redis.properties.subnetId : '' +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(redis.identity, 'principalId') ? redis.identity.principalId : '' + @description('The location the resource was deployed into.') output location string = redis.location @@ -264,6 +264,14 @@ output location string = redis.location // 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? diff --git a/modules/cache/redis/main.json b/modules/cache/redis/main.json index 5a9378fd0b..9a1a25ab90 100644 --- a/modules/cache/redis/main.json +++ b/modules/cache/redis/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "8286975131893372423" + "templateHash": "10917457453871237653" }, "name": "Redis Cache", "description": "This module deploys a Redis Cache.", "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": { @@ -393,18 +416,10 @@ "description": "Optional. Tags of the resource." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "enableNonSslPort": { @@ -565,11 +580,8 @@ }, "variables": { "availabilityZones": "[if(equals(parameters('skuName'), 'Premium'), if(parameters('zoneRedundant'), if(not(empty(parameters('zones'))), parameters('zones'), pickZones('Microsoft.Cache', 'redis', parameters('location'), 3)), createArray()), createArray())]", - "identityType": "[if(parameters('systemAssignedIdentity'), 'SystemAssigned', if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": { - "type": "[variables('identityType')]", - "userAssignedIdentities": "[if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), 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(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())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", @@ -1276,6 +1288,13 @@ }, "value": "[if(not(empty(parameters('subnetId'))), reference('redis').subnetId, '')]" }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('redis', '2022-06-01', 'full').identity, 'principalId')), reference('redis', '2022-06-01', 'full').identity.principalId, '')]" + }, "location": { "type": "string", "metadata": { diff --git a/modules/cognitive-services/account/.test/common/main.test.bicep b/modules/cognitive-services/account/.test/common/main.test.bicep index 9d515bae9e..a4c6701e77 100644 --- a/modules/cognitive-services/account/.test/common/main.test.bicep +++ b/modules/cognitive-services/account/.test/common/main.test.bicep @@ -109,9 +109,11 @@ module testDeployment '../../main.bicep' = { } ] sku: 'S0' - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } privateEndpoints: [ { diff --git a/modules/cognitive-services/account/.test/encr/main.test.bicep b/modules/cognitive-services/account/.test/encr/main.test.bicep index ad4bdf6ad6..442d5c02fb 100644 --- a/modules/cognitive-services/account/.test/encr/main.test.bicep +++ b/modules/cognitive-services/account/.test/encr/main.test.bicep @@ -61,8 +61,10 @@ module testDeployment '../../main.bicep' = { cMKUserAssignedIdentityResourceId: nestedDependencies.outputs.managedIdentityResourceId publicNetworkAccess: 'Enabled' sku: 'S0' - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } restrictOutboundNetworkAccess: false } diff --git a/modules/cognitive-services/account/.test/speech/main.test.bicep b/modules/cognitive-services/account/.test/speech/main.test.bicep index c341a3d3cb..d131eefbec 100644 --- a/modules/cognitive-services/account/.test/speech/main.test.bicep +++ b/modules/cognitive-services/account/.test/speech/main.test.bicep @@ -66,9 +66,11 @@ module testDeployment '../../main.bicep' = { } ] sku: 'S0' - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/cognitive-services/account/README.md b/modules/cognitive-services/account/README.md index a55ed7a0ae..e68d966293 100644 --- a/modules/cognitive-services/account/README.md +++ b/modules/cognitive-services/account/README.md @@ -74,6 +74,12 @@ module account 'br:bicep/modules/cognitive-services.account:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } networkAcls: { defaultAction: 'Deny' ipRules: [ @@ -109,15 +115,11 @@ module account 'br:bicep/modules/cognitive-services.account:1.0.0' = { } ] sku: 'S0' - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -170,6 +172,14 @@ module account 'br:bicep/modules/cognitive-services.account:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "networkAcls": { "value": { "defaultAction": "Deny", @@ -213,20 +223,12 @@ module account 'br:bicep/modules/cognitive-services.account:1.0.0' = { "sku": { "value": "S0" }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -253,12 +255,14 @@ module account 'br:bicep/modules/cognitive-services.account:1.0.0' = { cMKKeyVaultResourceId: '' cMKUserAssignedIdentityResourceId: '' enableDefaultTelemetry: '' + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } publicNetworkAccess: 'Enabled' restrictOutboundNetworkAccess: false sku: 'S0' - userAssignedIdentities: { - '': {} - } } } ``` @@ -295,6 +299,13 @@ module account 'br:bicep/modules/cognitive-services.account:1.0.0' = { "enableDefaultTelemetry": { "value": "" }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "publicNetworkAccess": { "value": "Enabled" }, @@ -303,11 +314,6 @@ module account 'br:bicep/modules/cognitive-services.account:1.0.0' = { }, "sku": { "value": "S0" - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -384,6 +390,12 @@ module account 'br:bicep/modules/cognitive-services.account:1.0.0' = { // Non-required parameters customSubDomainName: 'speechdomain' enableDefaultTelemetry: '' + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } privateEndpoints: [ { privateDnsZoneResourceIds: [ @@ -399,15 +411,11 @@ module account 'br:bicep/modules/cognitive-services.account:1.0.0' = { } ] sku: 'S0' - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -438,6 +446,14 @@ module account 'br:bicep/modules/cognitive-services.account:1.0.0' = { "enableDefaultTelemetry": { "value": "" }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "privateEndpoints": { "value": [ { @@ -457,20 +473,12 @@ module account 'br:bicep/modules/cognitive-services.account:1.0.0' = { "sku": { "value": "S0" }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -496,7 +504,6 @@ module account 'br:bicep/modules/cognitive-services.account:1.0.0' = { | [`cMKKeyVaultResourceId`](#parameter-cmkkeyvaultresourceid) | string | The resource ID of a key vault to reference a customer managed key for encryption from. Required if 'cMKKeyName' is not empty. | | [`cMKUserAssignedIdentityResourceId`](#parameter-cmkuserassignedidentityresourceid) | string | User assigned identity to use when fetching the customer managed key. Required if 'cMKKeyName' is not empty. | | [`customSubDomainName`](#parameter-customsubdomainname) | string | Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. | **Optional parameters** @@ -512,6 +519,7 @@ module account 'br:bicep/modules/cognitive-services.account:1.0.0' = { | [`enableDefaultTelemetry`](#parameter-enabledefaulttelemetry) | bool | Enable telemetry via a Globally Unique Identifier (GUID). | | [`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. | | [`migrationToken`](#parameter-migrationtoken) | string | Resource migration token. | | [`networkAcls`](#parameter-networkacls) | object | A collection of rules governing the accessibility 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. | @@ -520,7 +528,6 @@ module account 'br:bicep/modules/cognitive-services.account:1.0.0' = { | [`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'. | | [`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. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`userOwnedStorage`](#parameter-userownedstorage) | array | The storage accounts for this resource. | @@ -750,6 +757,32 @@ 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. Required if a user assigned identity is used for encryption. | + +### 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 if a user assigned identity is used for encryption. + +- Required: No +- Type: array + ### Parameter: `migrationToken` Resource migration token. @@ -1036,13 +1069,6 @@ SKU of the Cognitive Services resource. Use 'Get-AzCognitiveServicesAccountSku' - Default: `'S0'` - Allowed: `[C2, C3, C4, F0, F1, S, S0, S1, S10, S2, S3, S4, S5, S6, S7, S8, S9]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -1050,13 +1076,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `userOwnedStorage` The storage accounts for this resource. @@ -1074,7 +1093,7 @@ The storage accounts for this resource. | `name` | string | The name of the cognitive services account. | | `resourceGroupName` | string | The resource group the cognitive services account was deployed into. | | `resourceId` | string | The resource ID of the cognitive services account. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/cognitive-services/account/main.bicep b/modules/cognitive-services/account/main.bicep index bf97759606..395cd07b2e 100644 --- a/modules/cognitive-services/account/main.bicep +++ b/modules/cognitive-services/account/main.bicep @@ -77,11 +77,8 @@ param networkAcls object = {} @description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') param privateEndpoints privateEndpointType -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Conditional. The ID(s) to assign to the resource. Required if a user assigned identity is used for encryption.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. The lock settings of the service.') param lock lockType @@ -133,11 +130,11 @@ param enableDefaultTelemetry bool = true var enableReferencedModulesTelemetry = false -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 = { @@ -321,7 +318,7 @@ output resourceGroupName string = resourceGroup().name output endpoint string = cognitiveServices.properties.endpoint @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(cognitiveServices.identity, 'principalId') ? cognitiveServices.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(cognitiveServices.identity, 'principalId') ? cognitiveServices.identity.principalId : '' @description('The location the resource was deployed into.') output location string = cognitiveServices.location @@ -330,6 +327,14 @@ output location string = cognitiveServices.location // 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. Required if a user assigned identity is used for encryption.') + userAssignedResourcesIds: string[]? +}? + type lockType = { @description('Optional. Specify the name of lock.') name: string? diff --git a/modules/cognitive-services/account/main.json b/modules/cognitive-services/account/main.json index 6a47d37088..8921181da9 100644 --- a/modules/cognitive-services/account/main.json +++ b/modules/cognitive-services/account/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "15463203925377999389" + "templateHash": "12216590154280005113" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", "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. Required if a user assigned identity is used for encryption." + } + } + }, + "nullable": true + }, "lockType": { "type": "object", "properties": { @@ -468,18 +491,10 @@ "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Conditional. The ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + "description": "Optional. The managed identity definition for this resource." } }, "lock": { @@ -595,8 +610,8 @@ }, "variables": { "enableReferencedModulesTelemetry": false, - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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": { "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", @@ -1344,12 +1359,12 @@ }, "value": "[reference('cognitiveServices').endpoint]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('cognitiveServices', '2022-12-01', 'full').identity, 'principalId')), reference('cognitiveServices', '2022-12-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('cognitiveServices', '2022-12-01', 'full').identity, 'principalId')), reference('cognitiveServices', '2022-12-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/compute/disk-encryption-set/.test/accessPolicies/main.test.bicep b/modules/compute/disk-encryption-set/.test/accessPolicies/main.test.bicep index c2b4062ec7..be6f6c5b35 100644 --- a/modules/compute/disk-encryption-set/.test/accessPolicies/main.test.bicep +++ b/modules/compute/disk-encryption-set/.test/accessPolicies/main.test.bicep @@ -63,9 +63,11 @@ module testDeployment '../../main.bicep' = { principalType: 'ServicePrincipal' } ] - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/compute/disk-encryption-set/.test/common/main.test.bicep b/modules/compute/disk-encryption-set/.test/common/main.test.bicep index e061df91fc..f1dbf22a72 100644 --- a/modules/compute/disk-encryption-set/.test/common/main.test.bicep +++ b/modules/compute/disk-encryption-set/.test/common/main.test.bicep @@ -70,9 +70,10 @@ module testDeployment '../../main.bicep' = { principalType: 'ServicePrincipal' } ] - systemAssignedIdentity: false - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/compute/disk-encryption-set/README.md b/modules/compute/disk-encryption-set/README.md index ab8dcafd9f..c089521965 100644 --- a/modules/compute/disk-encryption-set/README.md +++ b/modules/compute/disk-encryption-set/README.md @@ -47,6 +47,12 @@ module diskEncryptionSet 'br:bicep/modules/compute.disk-encryption-set:1.0.0' = name: 'cdesap001' // Non-required parameters enableDefaultTelemetry: '' + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } roleAssignments: [ { principalId: '' @@ -54,15 +60,11 @@ module diskEncryptionSet 'br:bicep/modules/compute.disk-encryption-set:1.0.0' = roleDefinitionIdOrName: 'Reader' } ] - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -93,6 +95,14 @@ module diskEncryptionSet 'br:bicep/modules/compute.disk-encryption-set:1.0.0' = "enableDefaultTelemetry": { "value": "" }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "roleAssignments": { "value": [ { @@ -102,20 +112,12 @@ module diskEncryptionSet 'br:bicep/modules/compute.disk-encryption-set:1.0.0' = } ] }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -147,6 +149,11 @@ module diskEncryptionSet 'br:bicep/modules/compute.disk-encryption-set:1.0.0' = kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } roleAssignments: [ { principalId: '' @@ -154,15 +161,11 @@ module diskEncryptionSet 'br:bicep/modules/compute.disk-encryption-set:1.0.0' = roleDefinitionIdOrName: 'Reader' } ] - systemAssignedIdentity: false tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -199,6 +202,13 @@ module diskEncryptionSet 'br:bicep/modules/compute.disk-encryption-set:1.0.0' = "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "roleAssignments": { "value": [ { @@ -208,20 +218,12 @@ module diskEncryptionSet 'br:bicep/modules/compute.disk-encryption-set:1.0.0' = } ] }, - "systemAssignedIdentity": { - "value": false - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -241,13 +243,6 @@ module diskEncryptionSet 'br:bicep/modules/compute.disk-encryption-set:1.0.0' = | [`keyVaultResourceId`](#parameter-keyvaultresourceid) | string | Resource ID of the KeyVault containing the key or secret. | | [`name`](#parameter-name) | string | The name of the disk encryption set that is being created. | -**Conditional parameters** - -| Parameter | Type | Description | -| :-- | :-- | :-- | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. Required if userAssignedIdentities is empty. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. Required if systemAssignedIdentity is set to "false". | - **Optional parameters** | Parameter | Type | Description | @@ -258,6 +253,7 @@ module diskEncryptionSet 'br:bicep/modules/compute.disk-encryption-set:1.0.0' = | [`keyVersion`](#parameter-keyversion) | string | The version of the customer managed key to reference for encryption. If not provided, the latest key version is used. | | [`location`](#parameter-location) | string | Resource location. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. At least one identity type is required. | | [`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'. | | [`rotationToLatestKeyVersionEnabled`](#parameter-rotationtolatestkeyversionenabled) | bool | Set this flag to true to enable auto-updating of this disk encryption set to the latest key version. | | [`tags`](#parameter-tags) | object | Tags of the disk encryption resource. | @@ -337,6 +333,32 @@ Optional. Specify the name of lock. - Required: No - Type: string +### Parameter: `managedIdentities` + +The managed identity definition for this resource. At least one identity type is required. +- Required: Yes +- 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 disk encryption set that is being created. @@ -418,13 +440,6 @@ Set this flag to true to enable auto-updating of this disk encryption set to the - Type: bool - Default: `False` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. Required if userAssignedIdentities is empty. -- Required: No -- Type: bool -- Default: `True` - ### Parameter: `tags` Tags of the disk encryption resource. @@ -432,13 +447,6 @@ Tags of the disk encryption resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. Required if systemAssignedIdentity is set to "false". -- Required: No -- Type: object -- Default: `{object}` - ## Outputs @@ -448,9 +456,9 @@ The ID(s) to assign to the resource. Required if systemAssignedIdentity is set t | `keyVaultName` | string | The name of the key vault with the disk encryption key. | | `location` | string | The location the resource was deployed into. | | `name` | string | The name of the disk encryption set. | -| `principalId` | string | The principal ID of the disk encryption set. | | `resourceGroupName` | string | The resource group the disk encryption set was deployed into. | | `resourceId` | string | The resource ID of the disk encryption set. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/compute/disk-encryption-set/main.bicep b/modules/compute/disk-encryption-set/main.bicep index 217d90e175..d58f341dcb 100644 --- a/modules/compute/disk-encryption-set/main.bicep +++ b/modules/compute/disk-encryption-set/main.bicep @@ -33,11 +33,10 @@ param federatedClientId string = 'None' @description('Optional. Set this flag to true to enable auto-updating of this disk encryption set to the latest key version.') param rotationToLatestKeyVersionEnabled bool = false -@description('Conditional. Enables system assigned managed identity on the resource. Required if userAssignedIdentities is empty.') -param systemAssignedIdentity bool = true - -@description('Conditional. The ID(s) to assign to the resource. Required if systemAssignedIdentity is set to "false".') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource. At least one identity type is required.') +param managedIdentities managedIdentitiesType = { + systemAssigned: 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\'.') param roleAssignments roleAssignmentType @@ -48,12 +47,12 @@ param tags object = {} @description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') param enableDefaultTelemetry bool = true -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : 'UserAssigned' +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 = { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null -} +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 = { @@ -91,12 +90,12 @@ resource keyVault 'Microsoft.KeyVault/vaults@2021-10-01' existing = { } // Note: This is only enabled for user-assigned identities as the service's system-assigned identity isn't available during its initial deployment -module keyVaultPermissions 'modules/nested_keyVaultPermissions.bicep' = [for (userAssignedIdentityId, index) in items(userAssignedIdentities): { +module keyVaultPermissions 'modules/nested_keyVaultPermissions.bicep' = [for (userAssignedIdentityResourceId, index) in (managedIdentities.?userAssignedResourcesIds ?? []): { name: '${uniqueString(deployment().name, location)}-DiskEncrSet-KVPermissions-${index}' params: { keyName: keyName keyVaultResourceId: keyVaultResourceId - userAssignedIdentityResourceId: userAssignedIdentityId.key + userAssignedIdentityResourceId: userAssignedIdentityResourceId rbacAuthorizationEnabled: keyVault.properties.enableRbacAuthorization } scope: resourceGroup(split(keyVaultResourceId, '/')[2], split(keyVaultResourceId, '/')[4]) @@ -155,8 +154,8 @@ output name string = diskEncryptionSet.name @description('The resource group the disk encryption set was deployed into.') output resourceGroupName string = resourceGroup().name -@description('The principal ID of the disk encryption set.') -output principalId string = systemAssignedIdentity == true ? diskEncryptionSet.identity.principalId : '' +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(diskEncryptionSet.identity, 'principalId') ? diskEncryptionSet.identity.principalId : '' @description('The idenities of the disk encryption set.') output identities object = diskEncryptionSet.identity @@ -171,6 +170,14 @@ output location string = diskEncryptionSet.location // 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? diff --git a/modules/compute/disk-encryption-set/main.json b/modules/compute/disk-encryption-set/main.json index 79860c078c..bc9dabcebb 100644 --- a/modules/compute/disk-encryption-set/main.json +++ b/modules/compute/disk-encryption-set/main.json @@ -6,13 +6,35 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "580365923172310918" + "templateHash": "18120106263067507123" }, "name": "Disk Encryption Sets", "description": "This module deploys a Disk Encryption Set.", "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." + } + } + } + }, "lockType": { "type": "object", "properties": { @@ -169,18 +191,13 @@ "description": "Optional. Set this flag to true to enable auto-updating of this disk encryption set to the latest key version." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Conditional. Enables system assigned managed identity on the resource. Required if userAssignedIdentities is empty." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "defaultValue": { + "systemAssigned": true + }, "metadata": { - "description": "Conditional. The ID(s) to assign to the resource. Required if systemAssignedIdentity is set to \"false\"." + "description": "Optional. The managed identity definition for this resource. At least one identity type is required." } }, "roleAssignments": { @@ -205,11 +222,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), 'UserAssigned')]", - "identity": { - "type": "[variables('identityType')]", - "userAssignedIdentities": "[if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), 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(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')]", "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", @@ -319,7 +333,7 @@ "keyVaultPermissions": { "copy": { "name": "keyVaultPermissions", - "count": "[length(items(parameters('userAssignedIdentities')))]" + "count": "[length(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", @@ -339,7 +353,7 @@ "value": "[parameters('keyVaultResourceId')]" }, "userAssignedIdentityResourceId": { - "value": "[items(parameters('userAssignedIdentities'))[copyIndex()].key]" + "value": "[coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), createArray())[copyIndex()]]" }, "rbacAuthorizationEnabled": { "value": "[reference('keyVault').enableRbacAuthorization]" @@ -625,12 +639,12 @@ }, "value": "[resourceGroup().name]" }, - "principalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { - "description": "The principal ID of the disk encryption set." + "description": "The principal ID of the system assigned identity." }, - "value": "[if(equals(parameters('systemAssignedIdentity'), true()), reference('diskEncryptionSet', '2022-07-02', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('diskEncryptionSet', '2022-07-02', 'full').identity, 'principalId')), reference('diskEncryptionSet', '2022-07-02', 'full').identity.principalId, '')]" }, "identities": { "type": "object", diff --git a/modules/compute/virtual-machine-scale-set/.test/linux/main.test.bicep b/modules/compute/virtual-machine-scale-set/.test/linux/main.test.bicep index f8563a9b69..76e6e02285 100644 --- a/modules/compute/virtual-machine-scale-set/.test/linux/main.test.bicep +++ b/modules/compute/virtual-machine-scale-set/.test/linux/main.test.bicep @@ -191,11 +191,13 @@ module testDeployment '../../main.bicep' = { ] scaleSetFaultDomain: 1 skuCapacity: 1 - systemAssignedIdentity: true - upgradePolicyMode: 'Manual' - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } + upgradePolicyMode: 'Manual' vmNamePrefix: 'vmsslinvm' vmPriority: 'Regular' tags: { diff --git a/modules/compute/virtual-machine-scale-set/.test/windows/main.test.bicep b/modules/compute/virtual-machine-scale-set/.test/windows/main.test.bicep index 22bc5ff9ab..705d245b20 100644 --- a/modules/compute/virtual-machine-scale-set/.test/windows/main.test.bicep +++ b/modules/compute/virtual-machine-scale-set/.test/windows/main.test.bicep @@ -187,11 +187,13 @@ module testDeployment '../../main.bicep' = { } ] skuCapacity: 1 - systemAssignedIdentity: true - upgradePolicyMode: 'Manual' - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } + upgradePolicyMode: 'Manual' vmNamePrefix: 'vmsswinvm' vmPriority: 'Regular' tags: { diff --git a/modules/compute/virtual-machine-scale-set/README.md b/modules/compute/virtual-machine-scale-set/README.md index 94c34dbe2f..6835718941 100644 --- a/modules/compute/virtual-machine-scale-set/README.md +++ b/modules/compute/virtual-machine-scale-set/README.md @@ -141,6 +141,12 @@ module virtualMachineScaleSet 'br:bicep/modules/compute.virtual-machine-scale-se kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } nicConfigurations: [ { ipConfigurations: [ @@ -171,16 +177,12 @@ module virtualMachineScaleSet 'br:bicep/modules/compute.virtual-machine-scale-se ] scaleSetFaultDomain: 1 skuCapacity: 1 - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } upgradePolicyMode: 'Manual' - userAssignedIdentities: { - '': {} - } vmNamePrefix: 'vmsslinvm' vmPriority: 'Regular' } @@ -333,6 +335,14 @@ module virtualMachineScaleSet 'br:bicep/modules/compute.virtual-machine-scale-se "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "nicConfigurations": { "value": [ { @@ -373,9 +383,6 @@ module virtualMachineScaleSet 'br:bicep/modules/compute.virtual-machine-scale-se "skuCapacity": { "value": 1 }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", @@ -386,11 +393,6 @@ module virtualMachineScaleSet 'br:bicep/modules/compute.virtual-machine-scale-se "upgradePolicyMode": { "value": "Manual" }, - "userAssignedIdentities": { - "value": { - "": {} - } - }, "vmNamePrefix": { "value": "vmsslinvm" }, @@ -833,6 +835,12 @@ module virtualMachineScaleSet 'br:bicep/modules/compute.virtual-machine-scale-se kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } nicConfigurations: [ { ipConfigurations: [ @@ -857,16 +865,12 @@ module virtualMachineScaleSet 'br:bicep/modules/compute.virtual-machine-scale-se } ] skuCapacity: 1 - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } upgradePolicyMode: 'Manual' - userAssignedIdentities: { - '': {} - } vmNamePrefix: 'vmsswinvm' vmPriority: 'Regular' } @@ -1016,6 +1020,14 @@ module virtualMachineScaleSet 'br:bicep/modules/compute.virtual-machine-scale-se "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "nicConfigurations": { "value": [ { @@ -1048,9 +1060,6 @@ module virtualMachineScaleSet 'br:bicep/modules/compute.virtual-machine-scale-se "skuCapacity": { "value": 1 }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", @@ -1061,11 +1070,6 @@ module virtualMachineScaleSet 'br:bicep/modules/compute.virtual-machine-scale-se "upgradePolicyMode": { "value": "Manual" }, - "userAssignedIdentities": { - "value": { - "": {} - } - }, "vmNamePrefix": { "value": "vmsswinvm" }, @@ -1251,6 +1255,7 @@ module virtualMachineScaleSet 'br:bicep/modules/compute.virtual-machine-scale-se | [`licenseType`](#parameter-licensetype) | string | Specifies that the image or disk that is being used was licensed on-premises. This element is only used for images that contain the Windows Server operating system. | | [`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. | | [`maxBatchInstancePercent`](#parameter-maxbatchinstancepercent) | int | The maximum percent of total virtual machine instances that will be upgraded simultaneously by the rolling upgrade in one batch. As this is a maximum, unhealthy instances in previous or future batches can cause the percentage of instances in a batch to decrease to ensure higher reliability. | | [`maxPriceForLowPriorityVm`](#parameter-maxpriceforlowpriorityvm) | string | Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars. | | [`maxUnhealthyInstancePercent`](#parameter-maxunhealthyinstancepercent) | int | The maximum percentage of the total virtual machine instances in the scale set that can be simultaneously unhealthy, either as a result of being upgraded, or by being found in an unhealthy state by the virtual machine health checks before the rolling upgrade aborts. This constraint will be checked prior to starting any batch. | @@ -1272,12 +1277,10 @@ module virtualMachineScaleSet 'br:bicep/modules/compute.virtual-machine-scale-se | [`securityType`](#parameter-securitytype) | string | Specifies the SecurityType of the virtual machine scale set. It is set as TrustedLaunch to enable UefiSettings. | | [`singlePlacementGroup`](#parameter-singleplacementgroup) | bool | When true this limits the scale set to a single placement group, of max size 100 virtual machines. NOTE: If singlePlacementGroup is true, it may be modified to false. However, if singlePlacementGroup is false, it may not be modified to true. | | [`skuCapacity`](#parameter-skucapacity) | int | The initial instance count of scale set VMs. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`timeZone`](#parameter-timezone) | string | Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`. | | [`ultraSSDEnabled`](#parameter-ultrassdenabled) | bool | The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled. | | [`upgradePolicyMode`](#parameter-upgradepolicymode) | string | Specifies the mode of an upgrade to virtual machines in the scale set.' Manual - You control the application of updates to virtual machines in the scale set. You do this by using the manualUpgrade action. ; Automatic - All virtual machines in the scale set are automatically updated at the same time. - Automatic, Manual, Rolling. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`vmNamePrefix`](#parameter-vmnameprefix) | string | Specifies the computer name prefix for all of the virtual machines in the scale set. | | [`vmPriority`](#parameter-vmpriority) | string | Specifies the priority for the virtual machine. | | [`vTpmEnabled`](#parameter-vtpmenabled) | bool | Specifies whether vTPM should be enabled on the virtual machine scale set. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings. | @@ -1620,6 +1623,32 @@ 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: `maxBatchInstancePercent` The maximum percent of total virtual machine instances that will be upgraded simultaneously by the rolling upgrade in one batch. As this is a maximum, unhealthy instances in previous or future batches can cause the percentage of instances in a batch to decrease to ensure higher reliability. @@ -1860,13 +1889,6 @@ The SKU size of the VMs. - Required: Yes - Type: string -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -1896,13 +1918,6 @@ Specifies the mode of an upgrade to virtual machines in the scale set.' Manual - - Default: `'Manual'` - Allowed: `[Automatic, Manual, Rolling]` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `vmNamePrefix` Specifies the computer name prefix for all of the virtual machines in the scale set. @@ -1948,7 +1963,7 @@ Whether to force strictly even Virtual Machine distribution cross x-zones in cas | `name` | string | The name of the virtual machine scale set. | | `resourceGroupName` | string | The resource group of the virtual machine scale set. | | `resourceId` | string | The resource ID of the virtual machine scale set. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/compute/virtual-machine-scale-set/main.bicep b/modules/compute/virtual-machine-scale-set/main.bicep index 816b04bac2..cecffd62dd 100644 --- a/modules/compute/virtual-machine-scale-set/main.bicep +++ b/modules/compute/virtual-machine-scale-set/main.bicep @@ -253,11 +253,8 @@ param baseTime string = utcNow('u') @description('Optional. SAS token validity length to use to download files from storage accounts. Usage: \'PT8H\' - valid for 8 hours; \'P5D\' - valid for 5 days; \'P1Y\' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours.') param sasTokenValidityLength string = 'PT8H' -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType var publicKeysFormatted = [for publicKey in publicKeys: { path: publicKey.path @@ -290,11 +287,11 @@ var accountSasProperties = { signedProtocol: 'https' } -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 enableReferencedModulesTelemetry = false @@ -651,7 +648,7 @@ output resourceGroupName string = resourceGroup().name output name string = vmss.name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(vmss.identity, 'principalId') ? vmss.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(vmss.identity, 'principalId') ? vmss.identity.principalId : '' @description('The location the resource was deployed into.') output location string = vmss.location @@ -660,6 +657,14 @@ output location string = vmss.location // 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? diff --git a/modules/compute/virtual-machine-scale-set/main.json b/modules/compute/virtual-machine-scale-set/main.json index 40ef0e4559..e6a0a04847 100644 --- a/modules/compute/virtual-machine-scale-set/main.json +++ b/modules/compute/virtual-machine-scale-set/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "12670910144865793195" + "templateHash": "9859921411818274686" }, "name": "Virtual Machine Scale Sets", "description": "This module deploys a Virtual Machine Scale Set.", "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": { @@ -695,18 +718,10 @@ "description": "Optional. SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } } }, @@ -742,8 +757,8 @@ "signedResourceTypes": "o", "signedProtocol": "https" }, - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", @@ -2489,12 +2504,12 @@ }, "value": "[parameters('name')]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('vmss', '2022-11-01', 'full').identity, 'principalId')), reference('vmss', '2022-11-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('vmss', '2022-11-01', 'full').identity, 'principalId')), reference('vmss', '2022-11-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/compute/virtual-machine/.test/linux/main.test.bicep b/modules/compute/virtual-machine/.test/linux/main.test.bicep index 837c436af1..7832d8e74d 100644 --- a/modules/compute/virtual-machine/.test/linux/main.test.bicep +++ b/modules/compute/virtual-machine/.test/linux/main.test.bicep @@ -286,9 +286,11 @@ module testDeployment '../../main.bicep' = { principalType: 'ServicePrincipal' } ] - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/compute/virtual-machine/.test/windows/main.test.bicep b/modules/compute/virtual-machine/.test/windows/main.test.bicep index 430274c324..4d171f578e 100644 --- a/modules/compute/virtual-machine/.test/windows/main.test.bicep +++ b/modules/compute/virtual-machine/.test/windows/main.test.bicep @@ -307,9 +307,11 @@ module testDeployment '../../main.bicep' = { principalType: 'ServicePrincipal' } ] - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/compute/virtual-machine/README.md b/modules/compute/virtual-machine/README.md index 1e11679aeb..4b20b053d4 100644 --- a/modules/compute/virtual-machine/README.md +++ b/modules/compute/virtual-machine/README.md @@ -252,6 +252,12 @@ module virtualMachine 'br:bicep/modules/compute.virtual-machine:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } monitoringWorkspaceId: '' name: 'cvmlincom' patchMode: 'AutomaticByPlatform' @@ -268,15 +274,11 @@ module virtualMachine 'br:bicep/modules/compute.virtual-machine:1.0.0' = { roleDefinitionIdOrName: 'Reader' } ] - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -546,6 +548,14 @@ module virtualMachine 'br:bicep/modules/compute.virtual-machine:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "monitoringWorkspaceId": { "value": "" }, @@ -572,20 +582,12 @@ module virtualMachine 'br:bicep/modules/compute.virtual-machine:1.0.0' = { } ] }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -1148,6 +1150,12 @@ module virtualMachine 'br:bicep/modules/compute.virtual-machine:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } monitoringWorkspaceId: '' name: 'cvmwincom' patchMode: 'AutomaticByPlatform' @@ -1159,15 +1167,11 @@ module virtualMachine 'br:bicep/modules/compute.virtual-machine:1.0.0' = { roleDefinitionIdOrName: 'Reader' } ] - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -1462,6 +1466,14 @@ module virtualMachine 'br:bicep/modules/compute.virtual-machine:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "monitoringWorkspaceId": { "value": "" }, @@ -1483,20 +1495,12 @@ module virtualMachine 'br:bicep/modules/compute.virtual-machine:1.0.0' = { } ] }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -1968,6 +1972,7 @@ module virtualMachine 'br:bicep/modules/compute.virtual-machine:1.0.0' = { | [`licenseType`](#parameter-licensetype) | string | Specifies that the image or disk that is being used was licensed on-premises. This element is only used for images that contain the Windows Server operating system. | | [`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. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = "True". | | [`maxPriceForLowPriorityVm`](#parameter-maxpriceforlowpriorityvm) | string | Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars. | | [`monitoringWorkspaceId`](#parameter-monitoringworkspaceid) | string | Resource ID of the monitoring log analytics workspace. Must be set when extensionMonitoringAgentConfig is set to true. | | [`name`](#parameter-name) | string | The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory. If no value is provided, a 10 character long unique string will be generated based on the Resource Group's name. | @@ -1982,11 +1987,9 @@ module virtualMachine 'br:bicep/modules/compute.virtual-machine:1.0.0' = { | [`sasTokenValidityLength`](#parameter-sastokenvaliditylength) | string | SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours. | | [`secureBootEnabled`](#parameter-securebootenabled) | bool | Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings. | | [`securityType`](#parameter-securitytype) | string | Specifies the SecurityType of the virtual machine. It is set as TrustedLaunch to enable UefiSettings. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = "True". | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`timeZone`](#parameter-timezone) | string | Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`. | | [`ultraSSDEnabled`](#parameter-ultrassdenabled) | bool | The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`vTpmEnabled`](#parameter-vtpmenabled) | bool | Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings. | | [`winRM`](#parameter-winrm) | object | Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object. | @@ -2290,6 +2293,32 @@ Optional. Specify the name of lock. - Required: No - Type: string +### Parameter: `managedIdentities` + +The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = "True". +- 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: `maxPriceForLowPriorityVm` Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars. @@ -2471,13 +2500,6 @@ Specifies the SecurityType of the virtual machine. It is set as TrustedLaunch to - Type: string - Default: `''` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = "True". -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -2499,13 +2521,6 @@ The flag that enables or disables a capability to have one or more managed data - Type: bool - Default: `False` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `vmSize` Specifies the size for the VMs. @@ -2535,7 +2550,7 @@ Specifies the Windows Remote Management listeners. This enables remote Windows P | `name` | string | The name of the VM. | | `resourceGroupName` | string | The name of the resource group the VM was created in. | | `resourceId` | string | The resource ID of the VM. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/compute/virtual-machine/main.bicep b/modules/compute/virtual-machine/main.bicep index 891c2396a4..d90fbc7fff 100644 --- a/modules/compute/virtual-machine/main.bicep +++ b/modules/compute/virtual-machine/main.bicep @@ -81,11 +81,8 @@ param licenseType string = '' @description('Optional. The list of SSH public keys used to authenticate with linux based VMs.') param publicKeys array = [] -@description('Optional. Enables system assigned managed identity on the resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = "True".') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = "True".') +param managedIdentities managedIdentitiesType @description('Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled.') param bootDiagnostics bool = false @@ -297,22 +294,12 @@ var accountSasProperties = { signedProtocol: 'https' } -/* Determine Identity Type. - First, we determine if the System-Assigned Managed Identity should be enabled. - If AADJoin Extension is enabled then we automatically add SystemAssigned to the identityType because AADJoin requires the System-Assigned Managed Identity. - If the AADJoin Extension is not enabled then we add SystemAssigned to the identityType only if the value of the systemAssignedIdentity parameter is true. - Second, we determine if User Assigned Identities are assigned to the VM via the userAssignedIdentities parameter. - Third, we take the outcome of these two values and determine the identityType - If the System Identity and User Identities are assigned then the identityType is 'SystemAssigned,UserAssigned' - If only the system Identity is assigned then the identityType is 'SystemAssigned' - If only user managed Identities are assigned, then the identityType is 'UserAssigned' - Finally, if no identities are assigned, then the identityType is 'none'. -*/ -var identityType = (extensionAadJoinConfig.enabled ? true : systemAssignedIdentity) ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') - -var identity = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +var formattedUserAssignedIdentities = reduce(map((managedIdentities.?userAssignedResourcesIds ?? []), (id) => { '${id}': {} }), {}, (cur, next) => union(cur, next)) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +// If AADJoin Extension is enabled then we automatically enable SystemAssigned (required by AADJoin), otherwise we follow the usual logic. +var identity = !empty(managedIdentities) ? { + type: (extensionAadJoinConfig.enabled ? true : (managedIdentities.?systemAssigned ?? false)) ? (!empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null) + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } : null var enableReferencedModulesTelemetry = false @@ -697,7 +684,7 @@ output resourceId string = vm.id output resourceGroupName string = resourceGroup().name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(vm.identity, 'principalId') ? vm.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(vm.identity, 'principalId') ? vm.identity.principalId : '' @description('The location the resource was deployed into.') output location string = vm.location @@ -706,6 +693,14 @@ output location string = vm.location // 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? diff --git a/modules/compute/virtual-machine/main.json b/modules/compute/virtual-machine/main.json index 679af9ef5d..cb4a01ea7c 100644 --- a/modules/compute/virtual-machine/main.json +++ b/modules/compute/virtual-machine/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "5085746131014779064" + "templateHash": "10963953838389818589" }, "name": "Virtual Machines", "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.", "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": { @@ -372,18 +395,10 @@ "description": "Optional. The list of SSH public keys used to authenticate with linux based VMs." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." } }, "bootDiagnostics": { @@ -742,8 +757,8 @@ "signedResourceTypes": "o", "signedProtocol": "https" }, - "identityType": "[if(if(parameters('extensionAadJoinConfig').enabled, true(), parameters('systemAssignedIdentity')), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(if(parameters('extensionAadJoinConfig').enabled, true(), 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())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", @@ -4315,12 +4330,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('vm', '2022-11-01', 'full').identity, 'principalId')), reference('vm', '2022-11-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('vm', '2022-11-01', 'full').identity, 'principalId')), reference('vm', '2022-11-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/container-instance/container-group/.test/common/main.test.bicep b/modules/container-instance/container-group/.test/common/main.test.bicep index 2dc87dd5b1..6ba2e16a9d 100644 --- a/modules/container-instance/container-group/.test/common/main.test.bicep +++ b/modules/container-instance/container-group/.test/common/main.test.bicep @@ -112,9 +112,11 @@ module testDeployment '../../main.bicep' = { port: 443 } ] - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/container-instance/container-group/.test/encr/main.test.bicep b/modules/container-instance/container-group/.test/encr/main.test.bicep index be4c18e369..ade6cdb091 100644 --- a/modules/container-instance/container-group/.test/encr/main.test.bicep +++ b/modules/container-instance/container-group/.test/encr/main.test.bicep @@ -114,9 +114,11 @@ module testDeployment '../../main.bicep' = { port: 443 } ] - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } cMKKeyName: nestedDependencies.outputs.keyVaultEncryptionKeyName cMKKeyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId diff --git a/modules/container-instance/container-group/.test/private/main.test.bicep b/modules/container-instance/container-group/.test/private/main.test.bicep index 541422f6e5..8ca06b9dae 100644 --- a/modules/container-instance/container-group/.test/private/main.test.bicep +++ b/modules/container-instance/container-group/.test/private/main.test.bicep @@ -128,9 +128,11 @@ module testDeployment '../../main.bicep' = { name: 'my-name' } ] - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/container-instance/container-group/README.md b/modules/container-instance/container-group/README.md index b59196c147..21ae59f1f7 100644 --- a/modules/container-instance/container-group/README.md +++ b/modules/container-instance/container-group/README.md @@ -108,15 +108,17 @@ module containerGroup 'br:bicep/modules/container-instance.container-group:1.0.0 kind: 'CanNotDelete' name: 'myCustomLockName' } - systemAssignedIdentity: true + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -207,8 +209,13 @@ module containerGroup 'br:bicep/modules/container-instance.container-group:1.0.0 "name": "myCustomLockName" } }, - "systemAssignedIdentity": { - "value": true + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } }, "tags": { "value": { @@ -216,11 +223,6 @@ module containerGroup 'br:bicep/modules/container-instance.container-group:1.0.0 "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -306,15 +308,17 @@ module containerGroup 'br:bicep/modules/container-instance.container-group:1.0.0 kind: 'CanNotDelete' name: 'myCustomLockName' } - systemAssignedIdentity: true + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -414,8 +418,13 @@ module containerGroup 'br:bicep/modules/container-instance.container-group:1.0.0 "name": "myCustomLockName" } }, - "systemAssignedIdentity": { - "value": true + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } }, "tags": { "value": { @@ -423,11 +432,6 @@ module containerGroup 'br:bicep/modules/container-instance.container-group:1.0.0 "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -625,16 +629,18 @@ module containerGroup 'br:bicep/modules/container-instance.container-group:1.0.0 kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } subnetId: '' - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } volumes: [ { emptyDir: {} @@ -744,12 +750,17 @@ module containerGroup 'br:bicep/modules/container-instance.container-group:1.0.0 "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "subnetId": { "value": "" }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", @@ -757,11 +768,6 @@ module containerGroup 'br:bicep/modules/container-instance.container-group:1.0.0 "Role": "DeploymentValidation" } }, - "userAssignedIdentities": { - "value": { - "": {} - } - }, "volumes": { "value": [ { @@ -811,13 +817,12 @@ module containerGroup 'br:bicep/modules/container-instance.container-group:1.0.0 | [`ipAddressType`](#parameter-ipaddresstype) | string | Specifies if the IP is exposed to the public internet or private VNET. - Public or Private. | | [`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. | | [`osType`](#parameter-ostype) | string | The operating system type required by the containers in the container group. - Windows or Linux. | | [`restartPolicy`](#parameter-restartpolicy) | string | Restart policy for all containers within the container group. - Always: Always restart. OnFailure: Restart on failure. Never: Never restart. - Always, OnFailure, Never. | | [`sku`](#parameter-sku) | string | The container group SKU. | | [`subnetId`](#parameter-subnetid) | string | Resource ID of the subnet. Only specify when ipAddressType is Private. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`volumes`](#parameter-volumes) | array | Specify if volumes (emptyDir, AzureFileShare or GitRepo) shall be attached to your containergroup. | ### Parameter: `autoGeneratedDomainNameLabelScope` @@ -953,6 +958,32 @@ 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` Name for the container group. @@ -989,13 +1020,6 @@ Resource ID of the subnet. Only specify when ipAddressType is Private. - Type: string - Default: `''` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -1003,13 +1027,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `volumes` Specify if volumes (emptyDir, AzureFileShare or GitRepo) shall be attached to your containergroup. @@ -1027,7 +1044,7 @@ Specify if volumes (emptyDir, AzureFileShare or GitRepo) shall be attached to yo | `name` | string | The name of the container group. | | `resourceGroupName` | string | The resource group the container group was deployed into. | | `resourceId` | string | The resource ID of the container group. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/container-instance/container-group/main.bicep b/modules/container-instance/container-group/main.bicep index c6ae9e6363..ca4a2b89f7 100644 --- a/modules/container-instance/container-group/main.bicep +++ b/modules/container-instance/container-group/main.bicep @@ -66,11 +66,8 @@ param volumes array = [] @description('Optional. The lock settings of the service.') param lock lockType -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. Tags of the resource.') param tags object = {} @@ -97,11 +94,11 @@ param cMKKeyVersion string = '' @description('Conditional. User assigned identity to use when fetching the customer managed key. Required if \'cMKKeyName\' is not empty.') param cMKUserAssignedIdentityResourceId string = '' -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 resource defaultTelemetry 'Microsoft.Resources/deployments@2021-04-01' = if (enableDefaultTelemetry) { @@ -185,7 +182,7 @@ output resourceGroupName string = resourceGroup().name output iPv4Address string = containergroup.properties.ipAddress.ip @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(containergroup.identity, 'principalId') ? containergroup.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(containergroup.identity, 'principalId') ? containergroup.identity.principalId : '' @description('The location the resource was deployed into.') output location string = containergroup.location @@ -194,6 +191,14 @@ output location string = containergroup.location // 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? diff --git a/modules/container-instance/container-group/main.json b/modules/container-instance/container-group/main.json index 6d60f75d9f..5cbac36a8f 100644 --- a/modules/container-instance/container-group/main.json +++ b/modules/container-instance/container-group/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "745176097189380240" + "templateHash": "15669079272755728924" }, "name": "Container Instances Container Groups", "description": "This module deploys a Container Instance Container Group.", "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": { @@ -165,18 +188,10 @@ "description": "Optional. The lock settings of the service." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "tags": { @@ -234,8 +249,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]" }, "resources": { "cMKKeyVault::cMKKey": { @@ -329,12 +344,12 @@ }, "value": "[reference('containergroup').ipAddress.ip]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('containergroup', '2022-09-01', 'full').identity, 'principalId')), reference('containergroup', '2022-09-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('containergroup', '2022-09-01', 'full').identity, 'principalId')), reference('containergroup', '2022-09-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/container-registry/registry/.test/common/main.test.bicep b/modules/container-registry/registry/.test/common/main.test.bicep index 0abe517c6b..ff37a24ff3 100644 --- a/modules/container-registry/registry/.test/common/main.test.bicep +++ b/modules/container-registry/registry/.test/common/main.test.bicep @@ -128,11 +128,13 @@ module testDeployment '../../main.bicep' = { principalType: 'ServicePrincipal' } ] - systemAssignedIdentity: true - trustPolicyStatus: 'enabled' - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } + trustPolicyStatus: 'enabled' cacheRules: [ { name: 'customRule' diff --git a/modules/container-registry/registry/.test/encr/main.test.bicep b/modules/container-registry/registry/.test/encr/main.test.bicep index 3648f55a8f..6865689145 100644 --- a/modules/container-registry/registry/.test/encr/main.test.bicep +++ b/modules/container-registry/registry/.test/encr/main.test.bicep @@ -60,8 +60,10 @@ module testDeployment '../../main.bicep' = { cMKKeyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId cMKUserAssignedIdentityResourceId: nestedDependencies.outputs.managedIdentityResourceId publicNetworkAccess: 'Disabled' - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/container-registry/registry/README.md b/modules/container-registry/registry/README.md index ebf29d6d00..562b218164 100644 --- a/modules/container-registry/registry/README.md +++ b/modules/container-registry/registry/README.md @@ -86,6 +86,12 @@ module registry 'br:bicep/modules/container-registry.registry:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } networkRuleSetIpRules: [ { action: 'Allow' @@ -122,16 +128,12 @@ module registry 'br:bicep/modules/container-registry.registry:1.0.0' = { ] softDeletePolicyDays: 7 softDeletePolicyStatus: 'disabled' - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } trustPolicyStatus: 'enabled' - userAssignedIdentities: { - '': {} - } webhooks: [ { name: 'acrx001webhook' @@ -208,6 +210,14 @@ module registry 'br:bicep/modules/container-registry.registry:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "networkRuleSetIpRules": { "value": [ { @@ -258,9 +268,6 @@ module registry 'br:bicep/modules/container-registry.registry:1.0.0' = { "softDeletePolicyStatus": { "value": "disabled" }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", @@ -271,11 +278,6 @@ module registry 'br:bicep/modules/container-registry.registry:1.0.0' = { "trustPolicyStatus": { "value": "enabled" }, - "userAssignedIdentities": { - "value": { - "": {} - } - }, "webhooks": { "value": [ { @@ -309,15 +311,17 @@ module registry 'br:bicep/modules/container-registry.registry:1.0.0' = { cMKKeyVaultResourceId: '' cMKUserAssignedIdentityResourceId: '' enableDefaultTelemetry: '' + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } publicNetworkAccess: 'Disabled' tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -354,6 +358,13 @@ module registry 'br:bicep/modules/container-registry.registry:1.0.0' = { "enableDefaultTelemetry": { "value": "" }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "publicNetworkAccess": { "value": "Disabled" }, @@ -363,11 +374,6 @@ module registry 'br:bicep/modules/container-registry.registry:1.0.0' = { "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -546,6 +552,7 @@ module registry 'br:bicep/modules/container-registry.registry:1.0.0' = { | [`exportPolicyStatus`](#parameter-exportpolicystatus) | string | The value that indicates whether the export policy is enabled or not. | | [`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. | | [`networkRuleBypassOptions`](#parameter-networkrulebypassoptions) | string | Whether to allow trusted Azure services to access a network restricted registry. | | [`networkRuleSetDefaultAction`](#parameter-networkrulesetdefaultaction) | string | The default action of allow or deny when no other rules match. | | [`networkRuleSetIpRules`](#parameter-networkrulesetiprules) | array | The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'. | @@ -558,10 +565,8 @@ module registry 'br:bicep/modules/container-registry.registry:1.0.0' = { | [`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'. | | [`softDeletePolicyDays`](#parameter-softdeletepolicydays) | int | The number of days after which a soft-deleted item is permanently deleted. | | [`softDeletePolicyStatus`](#parameter-softdeletepolicystatus) | string | Soft Delete policy status. Default is disabled. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`trustPolicyStatus`](#parameter-trustpolicystatus) | string | The value that indicates whether the trust policy is enabled or not. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`webhooks`](#parameter-webhooks) | array | All webhooks to create. | | [`zoneRedundancy`](#parameter-zoneredundancy) | string | Whether or not zone redundancy is enabled for this container registry. | @@ -801,6 +806,32 @@ 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` Name of your Azure container registry. @@ -1119,13 +1150,6 @@ Soft Delete policy status. Default is disabled. - Default: `'disabled'` - Allowed: `[disabled, enabled]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -1141,13 +1165,6 @@ The value that indicates whether the trust policy is enabled or not. - Default: `'disabled'` - Allowed: `[disabled, enabled]` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `webhooks` All webhooks to create. @@ -1173,7 +1190,7 @@ Whether or not zone redundancy is enabled for this container registry. | `name` | string | The Name of the Azure container registry. | | `resourceGroupName` | string | The name of the Azure container registry. | | `resourceId` | string | The resource ID of the Azure container registry. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/container-registry/registry/main.bicep b/modules/container-registry/registry/main.bicep index 0208bf2c91..d936cb3207 100644 --- a/modules/container-registry/registry/main.bicep +++ b/modules/container-registry/registry/main.bicep @@ -119,11 +119,8 @@ param webhooks array = [] @description('Optional. The lock settings of the service.') param lock lockType -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. Tags of the resource.') param tags object = {} @@ -152,11 +149,11 @@ param cMKUserAssignedIdentityResourceId string = '' @description('Optional. Array of Cache Rules. Note: This is a preview feature ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache#cache-for-acr-preview)).') param cacheRules array = [] -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 enableReferencedModulesTelemetry = false @@ -386,7 +383,7 @@ output resourceGroupName string = resourceGroup().name output resourceId string = registry.id @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(registry.identity, 'principalId') ? registry.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(registry.identity, 'principalId') ? registry.identity.principalId : '' @description('The location the resource was deployed into.') output location string = registry.location @@ -395,6 +392,14 @@ output location string = registry.location // 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? diff --git a/modules/container-registry/registry/main.json b/modules/container-registry/registry/main.json index e1044592bd..1a70288241 100644 --- a/modules/container-registry/registry/main.json +++ b/modules/container-registry/registry/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "18353793336919307909" + "templateHash": "5299367951340146796" }, "name": "Azure Container Registries (ACR)", "description": "This module deploys an Azure Container Registry (ACR).", "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": { @@ -566,18 +589,10 @@ "description": "Optional. The lock settings of the service." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "tags": { @@ -644,8 +659,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", @@ -1900,12 +1915,12 @@ }, "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('registry', '2023-06-01-preview', 'full').identity, 'principalId')), reference('registry', '2023-06-01-preview', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('registry', '2023-06-01-preview', 'full').identity, 'principalId')), reference('registry', '2023-06-01-preview', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/container-service/managed-cluster/.test/azure/main.test.bicep b/modules/container-service/managed-cluster/.test/azure/main.test.bicep index 21a896e527..f1d65fbe4b 100644 --- a/modules/container-service/managed-cluster/.test/azure/main.test.bicep +++ b/modules/container-service/managed-cluster/.test/azure/main.test.bicep @@ -174,8 +174,10 @@ module testDeployment '../../main.bicep' = { enableStorageProfileDiskCSIDriver: true enableStorageProfileFileCSIDriver: true enableStorageProfileSnapshotController: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } identityProfile: { kubeletidentity: { diff --git a/modules/container-service/managed-cluster/.test/kubenet/main.test.bicep b/modules/container-service/managed-cluster/.test/kubenet/main.test.bicep index 9b7e0795fc..e0881cd6d5 100644 --- a/modules/container-service/managed-cluster/.test/kubenet/main.test.bicep +++ b/modules/container-service/managed-cluster/.test/kubenet/main.test.bicep @@ -156,8 +156,10 @@ module testDeployment '../../main.bicep' = { principalType: 'ServicePrincipal' } ] - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/container-service/managed-cluster/.test/min/main.test.bicep b/modules/container-service/managed-cluster/.test/min/main.test.bicep index ec5bf9306f..dc349e269b 100644 --- a/modules/container-service/managed-cluster/.test/min/main.test.bicep +++ b/modules/container-service/managed-cluster/.test/min/main.test.bicep @@ -40,7 +40,9 @@ module testDeployment '../../main.bicep' = { params: { name: '${namePrefix}${serviceShort}001' enableDefaultTelemetry: enableDefaultTelemetry - systemAssignedIdentity: true + managedIdentities: { + systemAssigned: true + } primaryAgentPoolProfile: [ { name: 'systempool' diff --git a/modules/container-service/managed-cluster/.test/priv/main.test.bicep b/modules/container-service/managed-cluster/.test/priv/main.test.bicep index df5967f188..90f3de3f7d 100644 --- a/modules/container-service/managed-cluster/.test/priv/main.test.bicep +++ b/modules/container-service/managed-cluster/.test/priv/main.test.bicep @@ -157,8 +157,10 @@ module testDeployment '../../main.bicep' = { } ] privateDNSZone: nestedDependencies.outputs.privateDnsZoneResourceId - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/container-service/managed-cluster/README.md b/modules/container-service/managed-cluster/README.md index b545850d90..0f65581013 100644 --- a/modules/container-service/managed-cluster/README.md +++ b/modules/container-service/managed-cluster/README.md @@ -214,6 +214,11 @@ module managedCluster 'br:bicep/modules/container-service.managed-cluster:1.0.0' kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } monitoringWorkspaceId: '' networkDataplane: 'azure' networkPlugin: 'azure' @@ -232,9 +237,6 @@ module managedCluster 'br:bicep/modules/container-service.managed-cluster:1.0.0' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -457,6 +459,13 @@ module managedCluster 'br:bicep/modules/container-service.managed-cluster:1.0.0' "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "monitoringWorkspaceId": { "value": "" }, @@ -490,11 +499,6 @@ module managedCluster 'br:bicep/modules/container-service.managed-cluster:1.0.0' "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -601,6 +605,11 @@ module managedCluster 'br:bicep/modules/container-service.managed-cluster:1.0.0' } ] enableDefaultTelemetry: '' + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } networkPlugin: 'kubenet' roleAssignments: [ { @@ -614,9 +623,6 @@ module managedCluster 'br:bicep/modules/container-service.managed-cluster:1.0.0' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -731,6 +737,13 @@ module managedCluster 'br:bicep/modules/container-service.managed-cluster:1.0.0' "enableDefaultTelemetry": { "value": "" }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "networkPlugin": { "value": "kubenet" }, @@ -749,11 +762,6 @@ module managedCluster 'br:bicep/modules/container-service.managed-cluster:1.0.0' "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -787,7 +795,9 @@ module managedCluster 'br:bicep/modules/container-service.managed-cluster:1.0.0' ] // Non-required parameters enableDefaultTelemetry: '' - systemAssignedIdentity: true + managedIdentities: { + systemAssigned: true + } } } ``` @@ -822,8 +832,10 @@ module managedCluster 'br:bicep/modules/container-service.managed-cluster:1.0.0' "enableDefaultTelemetry": { "value": "" }, - "systemAssignedIdentity": { - "value": true + "managedIdentities": { + "value": { + "systemAssigned": true + } } } } @@ -934,6 +946,11 @@ module managedCluster 'br:bicep/modules/container-service.managed-cluster:1.0.0' dnsServiceIP: '10.10.200.10' enableDefaultTelemetry: '' enablePrivateCluster: true + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } networkPlugin: 'azure' privateDNSZone: '' serviceCidr: '10.10.200.0/24' @@ -943,9 +960,6 @@ module managedCluster 'br:bicep/modules/container-service.managed-cluster:1.0.0' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -1068,6 +1082,13 @@ module managedCluster 'br:bicep/modules/container-service.managed-cluster:1.0.0' "enablePrivateCluster": { "value": true }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "networkPlugin": { "value": "azure" }, @@ -1086,11 +1107,6 @@ module managedCluster 'br:bicep/modules/container-service.managed-cluster:1.0.0' "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -1184,6 +1200,7 @@ module managedCluster 'br:bicep/modules/container-service.managed-cluster:1.0.0' | [`loadBalancerSku`](#parameter-loadbalancersku) | string | Specifies the sku of the load balancer used by the virtual machine scale sets used by nodepools. | | [`location`](#parameter-location) | string | Specifies the location of AKS cluster. It picks up Resource Group's location by default. | | [`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. | | [`managedOutboundIPCount`](#parameter-managedoutboundipcount) | int | Outbound IP Count for the Load balancer. | | [`monitoringWorkspaceId`](#parameter-monitoringworkspaceid) | string | Resource ID of the monitoring log analytics workspace. | | [`networkDataplane`](#parameter-networkdataplane) | string | Network dataplane used in the Kubernetes cluster. Not compatible with kubenet network plugin. | @@ -1205,9 +1222,7 @@ module managedCluster 'br:bicep/modules/container-service.managed-cluster:1.0.0' | [`skuTier`](#parameter-skutier) | string | Tier of a managed cluster SKU. - Free or Standard. | | [`sshPublicKey`](#parameter-sshpublickey) | string | Specifies the SSH RSA public key string for the Linux nodes. | | [`supportPlan`](#parameter-supportplan) | string | The support plan for the Managed Cluster. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`webApplicationRoutingEnabled`](#parameter-webapplicationroutingenabled) | bool | Specifies whether the webApplicationRoutingEnabled add-on is enabled or not. | ### Parameter: `aadProfileAdminGroupObjectIDs` @@ -1807,6 +1822,32 @@ Optional. Specify the name of lock. - Required: No - Type: string +### Parameter: `managedIdentities` + +The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both. +- 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: `managedOutboundIPCount` Outbound IP Count for the Load balancer. @@ -2034,13 +2075,6 @@ The support plan for the Managed Cluster. - Default: `'KubernetesOfficial'` - Allowed: `[AKSLongTermSupport, KubernetesOfficial]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -2048,13 +2082,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `webApplicationRoutingEnabled` Specifies whether the webApplicationRoutingEnabled add-on is enabled or not. @@ -2078,7 +2105,7 @@ Specifies whether the webApplicationRoutingEnabled add-on is enabled or not. | `omsagentIdentityObjectId` | string | The Object ID of the OMS agent identity. | | `resourceGroupName` | string | The resource group the managed cluster was deployed into. | | `resourceId` | string | The resource ID of the managed cluster. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/container-service/managed-cluster/main.bicep b/modules/container-service/managed-cluster/main.bicep index 06b427922c..b9f7f16414 100644 --- a/modules/container-service/managed-cluster/main.bicep +++ b/modules/container-service/managed-cluster/main.bicep @@ -11,11 +11,8 @@ param location string = resourceGroup().location @description('Optional. Specifies the DNS prefix specified when creating the managed cluster.') param dnsPrefix string = name -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both.') +param managedIdentities managedIdentitiesType @description('Optional. Network dataplane used in the Kubernetes cluster. Not compatible with kubenet network plugin.') @allowed([ @@ -351,12 +348,12 @@ param httpProxyConfig object = {} @description('Optional. Identities associated with the cluster.') param identityProfile object = {} -var identityType = systemAssignedIdentity ? 'SystemAssigned' : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null -} +var identity = !empty(managedIdentities) ? { + type: (managedIdentities.?systemAssigned ?? false) ? 'SystemAssigned' : (!empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null) + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null +} : null var linuxProfile = { adminUsername: adminUsername @@ -706,7 +703,7 @@ output name string = managedCluster.name output controlPlaneFQDN string = enablePrivateCluster ? managedCluster.properties.privateFQDN : managedCluster.properties.fqdn @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(managedCluster.identity, 'principalId') ? managedCluster.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(managedCluster.identity, 'principalId') ? managedCluster.identity.principalId : '' @description('The Object ID of the AKS identity.') output kubeletidentityObjectId string = contains(managedCluster.properties, 'identityProfile') ? contains(managedCluster.properties.identityProfile, 'kubeletidentity') ? managedCluster.properties.identityProfile.kubeletidentity.objectId : '' : '' @@ -733,6 +730,14 @@ output addonProfiles object = contains(managedCluster.properties, 'addonProfiles // 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? diff --git a/modules/container-service/managed-cluster/main.json b/modules/container-service/managed-cluster/main.json index 16afb7ba6d..b35df3cf30 100644 --- a/modules/container-service/managed-cluster/main.json +++ b/modules/container-service/managed-cluster/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "10746697295674152111" + "templateHash": "10186677383934049186" }, "name": "Azure Kubernetes Service (AKS) Managed Clusters", "description": "This module deploys an Azure Kubernetes Service (AKS) Managed Cluster.", "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": { @@ -232,18 +255,10 @@ "description": "Optional. Specifies the DNS prefix specified when creating the managed cluster." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." } }, "networkDataplane": { @@ -926,11 +941,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), 'SystemAssigned', if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": { - "type": "[variables('identityType')]", - "userAssignedIdentities": "[if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), 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(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "linuxProfile": { "adminUsername": "[parameters('adminUsername')]", "ssh": { @@ -2093,12 +2105,12 @@ }, "value": "[if(parameters('enablePrivateCluster'), reference('managedCluster').privateFQDN, reference('managedCluster').fqdn)]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('managedCluster', '2023-07-02-preview', 'full').identity, 'principalId')), reference('managedCluster', '2023-07-02-preview', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('managedCluster', '2023-07-02-preview', 'full').identity, 'principalId')), reference('managedCluster', '2023-07-02-preview', 'full').identity.principalId, '')]" }, "kubeletidentityObjectId": { "type": "string", diff --git a/modules/data-factory/factory/.test/common/main.test.bicep b/modules/data-factory/factory/.test/common/main.test.bicep index 16dc9777fd..84cd092e7e 100644 --- a/modules/data-factory/factory/.test/common/main.test.bicep +++ b/modules/data-factory/factory/.test/common/main.test.bicep @@ -144,9 +144,11 @@ module testDeployment '../../main.bicep' = { principalType: 'ServicePrincipal' } ] - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/data-factory/factory/README.md b/modules/data-factory/factory/README.md index f8be417ef4..cae941fa39 100644 --- a/modules/data-factory/factory/README.md +++ b/modules/data-factory/factory/README.md @@ -97,6 +97,12 @@ module factory 'br:bicep/modules/data-factory.factory:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } managedPrivateEndpoints: [ { fqdns: [ @@ -127,15 +133,11 @@ module factory 'br:bicep/modules/data-factory.factory:1.0.0' = { roleDefinitionIdOrName: 'Reader' } ] - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -220,6 +222,14 @@ module factory 'br:bicep/modules/data-factory.factory:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "managedPrivateEndpoints": { "value": [ { @@ -258,20 +268,12 @@ module factory 'br:bicep/modules/data-factory.factory:1.0.0' = { } ] }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -365,14 +367,13 @@ module factory 'br:bicep/modules/data-factory.factory:1.0.0' = { | [`integrationRuntimes`](#parameter-integrationruntimes) | array | An array of objects for the configuration of an Integration Runtime. | | [`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. | | [`managedPrivateEndpoints`](#parameter-managedprivateendpoints) | array | An array of managed private endpoints objects created in the Data Factory managed virtual network. | | [`managedVirtualNetworkName`](#parameter-managedvirtualnetworkname) | string | The name of the Managed Virtual Network. | | [`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. | | [`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'. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | ### Parameter: `cMKKeyName` @@ -635,6 +636,32 @@ 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: `managedPrivateEndpoints` An array of managed private endpoints objects created in the Data Factory managed virtual network. @@ -899,13 +926,6 @@ Required. The name of the role to assign. If it cannot be found you can specify - Required: Yes - Type: string -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -913,13 +933,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs @@ -929,7 +942,7 @@ The ID(s) to assign to the resource. | `name` | string | The Name of the Azure Data Factory instance. | | `resourceGroupName` | string | The name of the Resource Group with the Data factory. | | `resourceId` | string | The Resource ID of the Data factory. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/data-factory/factory/main.bicep b/modules/data-factory/factory/main.bicep index 5051acac34..b8cce9bea8 100644 --- a/modules/data-factory/factory/main.bicep +++ b/modules/data-factory/factory/main.bicep @@ -61,11 +61,8 @@ param diagnosticSettings diagnosticSettingType @description('Optional. The lock settings of the service.') param lock lockType -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. Configuration Details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') param privateEndpoints privateEndpointType @@ -91,11 +88,11 @@ param tags object = {} @description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') param enableDefaultTelemetry bool = true -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 enableReferencedModulesTelemetry = false @@ -264,7 +261,7 @@ output resourceId string = dataFactory.id output resourceGroupName string = resourceGroup().name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(dataFactory.identity, 'principalId') ? dataFactory.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(dataFactory.identity, 'principalId') ? dataFactory.identity.principalId : '' @description('The location the resource was deployed into.') output location string = dataFactory.location @@ -273,6 +270,14 @@ output location string = dataFactory.location // 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? diff --git a/modules/data-factory/factory/main.json b/modules/data-factory/factory/main.json index b4d1ee215d..11658501f0 100644 --- a/modules/data-factory/factory/main.json +++ b/modules/data-factory/factory/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "12744321553281451212" + "templateHash": "4712647299782394769" }, "name": "Data Factories", "description": "This module deploys a Data Factory.", "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": { @@ -489,18 +512,10 @@ "description": "Optional. The lock settings of the service." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "privateEndpoints": { @@ -559,8 +574,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", @@ -1655,12 +1670,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('dataFactory', '2018-06-01', 'full').identity, 'principalId')), reference('dataFactory', '2018-06-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('dataFactory', '2018-06-01', 'full').identity, 'principalId')), reference('dataFactory', '2018-06-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/data-protection/backup-vault/.test/common/main.test.bicep b/modules/data-protection/backup-vault/.test/common/main.test.bicep index 286a2b51c5..5a9de2cea8 100644 --- a/modules/data-protection/backup-vault/.test/common/main.test.bicep +++ b/modules/data-protection/backup-vault/.test/common/main.test.bicep @@ -60,7 +60,9 @@ module testDeployment '../../main.bicep' = { } ] azureMonitorAlertSettingsAlertsForAllJobFailures: 'Disabled' - systemAssignedIdentity: true + managedIdentities: { + systemAssigned: true + } backupPolicies: [ { name: 'DefaultPolicy' diff --git a/modules/data-protection/backup-vault/README.md b/modules/data-protection/backup-vault/README.md index 22e624a5c0..94825fc794 100644 --- a/modules/data-protection/backup-vault/README.md +++ b/modules/data-protection/backup-vault/README.md @@ -115,6 +115,9 @@ module backupVault 'br:bicep/modules/data-protection.backup-vault:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + } roleAssignments: [ { principalId: '' @@ -122,7 +125,6 @@ module backupVault 'br:bicep/modules/data-protection.backup-vault:1.0.0' = { roleDefinitionIdOrName: 'Reader' } ] - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -225,6 +227,11 @@ module backupVault 'br:bicep/modules/data-protection.backup-vault:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, "roleAssignments": { "value": [ { @@ -234,9 +241,6 @@ module backupVault 'br:bicep/modules/data-protection.backup-vault:1.0.0' = { } ] }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", @@ -319,9 +323,9 @@ module backupVault 'br:bicep/modules/data-protection.backup-vault:1.0.0' = { | [`featureSettings`](#parameter-featuresettings) | object | Feature settings for the backup vault. | | [`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. | | [`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'. | | [`securitySettings`](#parameter-securitysettings) | object | Security settings for the backup vault. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the Recovery Service Vault resource. | | [`type`](#parameter-type) | string | The vault redundancy level to use. | @@ -396,6 +400,24 @@ 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. | + +### Parameter: `managedIdentities.systemAssigned` + +Optional. Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + ### Parameter: `name` Name of the Backup Vault. @@ -477,13 +499,6 @@ Security settings for the backup vault. - Type: object - Default: `{object}` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the Recovery Service Vault resource. @@ -508,7 +523,7 @@ The vault redundancy level to use. | `name` | string | The Name of the backup vault. | | `resourceGroupName` | string | The name of the resource group the recovery services vault was created in. | | `resourceId` | string | The resource ID of the backup vault. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/data-protection/backup-vault/main.bicep b/modules/data-protection/backup-vault/main.bicep index caab5b84fa..042be9825e 100644 --- a/modules/data-protection/backup-vault/main.bicep +++ b/modules/data-protection/backup-vault/main.bicep @@ -17,8 +17,8 @@ param roleAssignments roleAssignmentType @description('Optional. The lock settings of the service.') param lock lockType -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. Tags of the Recovery Service Vault resource.') param tags object = {} @@ -55,10 +55,8 @@ param securitySettings object = {} @description('Optional. Feature settings for the backup vault.') param featureSettings object = {} -var identityType = systemAssignedIdentity ? 'SystemAssigned' : 'None' - -var identity = identityType != 'None' ? { - type: identityType +var identity = !empty(managedIdentities) ? { + type: (managedIdentities.?systemAssigned ?? false) ? 'SystemAssigned' : null } : null var enableReferencedModulesTelemetry = false @@ -151,7 +149,7 @@ output resourceGroupName string = resourceGroup().name output name string = backupVault.name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(backupVault.identity, 'principalId') ? backupVault.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(backupVault.identity, 'principalId') ? backupVault.identity.principalId : '' @description('The location the resource was deployed into.') output location string = backupVault.location @@ -160,6 +158,11 @@ output location string = backupVault.location // Definitions // // =============== // +type managedIdentitiesType = { + @description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? +}? + type lockType = { @description('Optional. Specify the name of lock.') name: string? diff --git a/modules/data-protection/backup-vault/main.json b/modules/data-protection/backup-vault/main.json index 868f140db9..9db6f483b0 100644 --- a/modules/data-protection/backup-vault/main.json +++ b/modules/data-protection/backup-vault/main.json @@ -6,13 +6,26 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "8939931538076574162" + "templateHash": "11392074106571494077" }, "name": "Data Protection Backup Vaults", "description": "This module deploys a Data Protection Backup Vault.", "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." + } + } + }, + "nullable": true + }, "lockType": { "type": "object", "properties": { @@ -138,11 +151,10 @@ "description": "Optional. The lock settings of the service." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." + "description": "Optional. The managed identity definition for this resource." } }, "tags": { @@ -210,8 +222,7 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), 'SystemAssigned', 'None')]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType')), null())]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e467623-bb1f-42f4-a55d-6e525e11384b')]", @@ -441,12 +452,12 @@ }, "value": "[parameters('name')]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('backupVault', '2023-05-01', 'full').identity, 'principalId')), reference('backupVault', '2023-05-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('backupVault', '2023-05-01', 'full').identity, 'principalId')), reference('backupVault', '2023-05-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/databricks/access-connector/.test/common/main.test.bicep b/modules/databricks/access-connector/.test/common/main.test.bicep index 1c6ad77107..c4d988caa7 100644 --- a/modules/databricks/access-connector/.test/common/main.test.bicep +++ b/modules/databricks/access-connector/.test/common/main.test.bicep @@ -56,9 +56,11 @@ module testDeployment '../../main.bicep' = { kind: 'CanNotDelete' name: 'myCustomLockName' } - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } roleAssignments: [ { diff --git a/modules/databricks/access-connector/README.md b/modules/databricks/access-connector/README.md index c965dbdf4f..796b14a8bf 100644 --- a/modules/databricks/access-connector/README.md +++ b/modules/databricks/access-connector/README.md @@ -51,6 +51,12 @@ module accessConnector 'br:bicep/modules/databricks.access-connector:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } roleAssignments: [ { principalId: '' @@ -58,15 +64,11 @@ module accessConnector 'br:bicep/modules/databricks.access-connector:1.0.0' = { roleDefinitionIdOrName: 'Reader' } ] - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -100,6 +102,14 @@ module accessConnector 'br:bicep/modules/databricks.access-connector:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "roleAssignments": { "value": [ { @@ -109,20 +119,12 @@ module accessConnector 'br:bicep/modules/databricks.access-connector:1.0.0' = { } ] }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -195,10 +197,9 @@ module accessConnector 'br:bicep/modules/databricks.access-connector:1.0.0' = { | [`enableDefaultTelemetry`](#parameter-enabledefaulttelemetry) | bool | Enable telemetry via a Globally Unique Identifier (GUID). | | [`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. | | [`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'. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The set of user assigned identities associated with the resource, the userAssignedIdentities dictionary keys will be ARM resource IDs and The dictionary values can be empty objects ({}) in requests. | ### Parameter: `enableDefaultTelemetry` @@ -241,6 +242,32 @@ 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 Azure Databricks access connector to create. @@ -315,13 +342,6 @@ Required. The name of the role to assign. If it cannot be found you can specify - Required: Yes - Type: string -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -329,13 +349,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The set of user assigned identities associated with the resource, the userAssignedIdentities dictionary keys will be ARM resource IDs and The dictionary values can be empty objects ({}) in requests. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs @@ -345,6 +358,7 @@ The set of user assigned identities associated with the resource, the userAssign | `name` | string | The name of the deployed access connector. | | `resourceGroupName` | string | The resource group of the deployed access connector. | | `resourceId` | string | The resource ID of the deployed access connector. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/databricks/access-connector/main.bicep b/modules/databricks/access-connector/main.bicep index ca7d88ef21..d8ce4aeee9 100644 --- a/modules/databricks/access-connector/main.bicep +++ b/modules/databricks/access-connector/main.bicep @@ -17,20 +17,17 @@ param roleAssignments roleAssignmentType @description('Optional. The lock settings of the service.') param lock lockType -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The set of user assigned identities associated with the resource, the userAssignedIdentities dictionary keys will be ARM resource IDs and The dictionary values can be empty objects ({}) in requests.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') param enableDefaultTelemetry bool = true -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 = { @@ -93,6 +90,9 @@ output resourceId string = accessConnector.id @description('The resource group of the deployed access connector.') output resourceGroupName string = resourceGroup().name +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(accessConnector.identity, 'principalId') ? accessConnector.identity.principalId : '' + @description('The location the resource was deployed into.') output location string = accessConnector.location @@ -100,6 +100,14 @@ output location string = accessConnector.location // 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? diff --git a/modules/databricks/access-connector/main.json b/modules/databricks/access-connector/main.json index 6098e38098..5e8014b2f2 100644 --- a/modules/databricks/access-connector/main.json +++ b/modules/databricks/access-connector/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "11496388120257494229" + "templateHash": "9757807827728921562" }, "name": "Azure Databricks Access Connectors", "description": "This module deploys an Azure Databricks Access Connector.", "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": { @@ -138,18 +161,10 @@ "description": "Optional. The lock settings of the service." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The set of user assigned identities associated with the resource, the userAssignedIdentities dictionary keys will be ARM resource IDs and The dictionary values can be empty objects ({}) in requests." + "description": "Optional. The managed identity definition for this resource." } }, "enableDefaultTelemetry": { @@ -161,8 +176,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", @@ -254,6 +269,13 @@ }, "value": "[resourceGroup().name]" }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('accessConnector', '2022-10-01-preview', 'full').identity, 'principalId')), reference('accessConnector', '2022-10-01-preview', 'full').identity.principalId, '')]" + }, "location": { "type": "string", "metadata": { diff --git a/modules/db-for-my-sql/flexible-server/.test/private/main.test.bicep b/modules/db-for-my-sql/flexible-server/.test/private/main.test.bicep index 50b1602869..13819511a9 100644 --- a/modules/db-for-my-sql/flexible-server/.test/private/main.test.bicep +++ b/modules/db-for-my-sql/flexible-server/.test/private/main.test.bicep @@ -103,8 +103,10 @@ module testDeployment '../../main.bicep' = { ] highAvailability: 'SameZone' storageAutoGrow: 'Enabled' - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } diagnosticSettings: [ { diff --git a/modules/db-for-my-sql/flexible-server/.test/public/main.test.bicep b/modules/db-for-my-sql/flexible-server/.test/public/main.test.bicep index 4b29cd3672..04f9296d26 100644 --- a/modules/db-for-my-sql/flexible-server/.test/public/main.test.bicep +++ b/modules/db-for-my-sql/flexible-server/.test/public/main.test.bicep @@ -150,9 +150,11 @@ module testDeployment '../../main.bicep' = { geoBackupCMKKeyVaultResourceId: nestedDependencies2.outputs.geoBackupKeyVaultResourceId geoBackupCMKKeyName: nestedDependencies2.outputs.geoBackupKeyName geoBackupCMKUserAssignedIdentityResourceId: nestedDependencies2.outputs.geoBackupManagedIdentityResourceId - userAssignedIdentities: { - '${nestedDependencies2.outputs.managedIdentityResourceId}': {} - '${nestedDependencies2.outputs.geoBackupManagedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies2.outputs.managedIdentityResourceId + nestedDependencies2.outputs.geoBackupManagedIdentityResourceId + ] } diagnosticSettings: [ { diff --git a/modules/db-for-my-sql/flexible-server/README.md b/modules/db-for-my-sql/flexible-server/README.md index b606760ece..ac8fa8150a 100644 --- a/modules/db-for-my-sql/flexible-server/README.md +++ b/modules/db-for-my-sql/flexible-server/README.md @@ -150,6 +150,11 @@ module flexibleServer 'br:bicep/modules/db-for-my-sql.flexible-server:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } privateDnsZoneResourceId: '' roleAssignments: [ { @@ -167,9 +172,6 @@ module flexibleServer 'br:bicep/modules/db-for-my-sql.flexible-server:1.0.0' = { resourceType: 'MySQL Flexible Server' serverName: 'dfmsfspvt001' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -256,6 +258,13 @@ module flexibleServer 'br:bicep/modules/db-for-my-sql.flexible-server:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "privateDnsZoneResourceId": { "value": "" }, @@ -286,11 +295,6 @@ module flexibleServer 'br:bicep/modules/db-for-my-sql.flexible-server:1.0.0' = { "resourceType": "MySQL Flexible Server", "serverName": "dfmsfspvt001" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -373,6 +377,12 @@ module flexibleServer 'br:bicep/modules/db-for-my-sql.flexible-server:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + userAssignedResourcesIds: [ + '' + '' + ] + } roleAssignments: [ { principalId: '' @@ -389,10 +399,6 @@ module flexibleServer 'br:bicep/modules/db-for-my-sql.flexible-server:1.0.0' = { resourceType: 'MySQL Flexible Server' serverName: 'dfmsfsp001' } - userAssignedIdentities: { - '': {} - '': {} - } version: '8.0.21' } } @@ -516,6 +522,14 @@ module flexibleServer 'br:bicep/modules/db-for-my-sql.flexible-server:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "", + "" + ] + } + }, "roleAssignments": { "value": [ { @@ -544,12 +558,6 @@ module flexibleServer 'br:bicep/modules/db-for-my-sql.flexible-server:1.0.0' = { "serverName": "dfmsfsp001" } }, - "userAssignedIdentities": { - "value": { - "": {}, - "": {} - } - }, "version": { "value": "8.0.21" } @@ -579,11 +587,11 @@ module flexibleServer 'br:bicep/modules/db-for-my-sql.flexible-server:1.0.0' = { | [`cMKUserAssignedIdentityResourceId`](#parameter-cmkuserassignedidentityresourceid) | string | User assigned identity to use when fetching the customer managed key. The identity should have key usage permissions on the Key Vault Key. Required if "cMKKeyName" is not empty. | | [`geoBackupCMKKeyVaultResourceId`](#parameter-geobackupcmkkeyvaultresourceid) | string | The resource ID of a key vault to reference a customer managed key for encryption from. Required if "cMKKeyName" is not empty and geoRedundantBackup is "Enabled". | | [`geoBackupCMKUserAssignedIdentityResourceId`](#parameter-geobackupcmkuserassignedidentityresourceid) | string | Geo backup user identity resource ID as identity cant cross region, need identity in same region as geo backup. The identity should have key usage permissions on the Key Vault Key. Required if "cMKKeyName" is not empty and geoRedundantBackup is "Enabled". | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. Required if 'cMKKeyName' is not empty. | | [`privateDnsZoneResourceId`](#parameter-privatednszoneresourceid) | string | Private dns zone arm resource ID. Used when the desired connectivity mode is "Private Access". Required if "delegatedSubnetResourceId" is used and the Private DNS Zone name must end with mysql.database.azure.com in order to be linked to the MySQL Flexible Server. | | [`restorePointInTime`](#parameter-restorepointintime) | string | Restore point creation time (ISO8601 format), specifying the time to restore from. Required if "createMode" is set to "PointInTimeRestore". | | [`sourceServerResourceId`](#parameter-sourceserverresourceid) | string | The source MySQL server ID. Required if "createMode" is set to "PointInTimeRestore". | | [`storageAutoGrow`](#parameter-storageautogrow) | string | Enable Storage Auto Grow or not. Storage auto-growth prevents a server from running out of storage and becoming read-only. Required if "highAvailability" is not "Disabled". | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. Required if "cMKKeyName" is not empty. | **Optional parameters** @@ -917,6 +925,24 @@ Properties for the maintenence window. If provided, "customWindow" property must - Type: object - Default: `{object}` +### Parameter: `managedIdentities` + +The managed identity definition for this resource. Required if 'cMKKeyName' is not empty. +- 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` The name of the MySQL flexible server. @@ -1071,13 +1097,6 @@ The tier of the particular SKU. Tier must align with the "skuName" property. Exa - Type: string - Allowed: `[Burstable, GeneralPurpose, MemoryOptimized]` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. Required if "cMKKeyName" is not empty. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `version` MySQL Server version. diff --git a/modules/db-for-my-sql/flexible-server/main.bicep b/modules/db-for-my-sql/flexible-server/main.bicep index 8ee3664d6e..9df9e895a6 100644 --- a/modules/db-for-my-sql/flexible-server/main.bicep +++ b/modules/db-for-my-sql/flexible-server/main.bicep @@ -65,8 +65,8 @@ param geoRedundantBackup string = 'Disabled' @description('Optional. The mode to create a new MySQL server.') param createMode string = 'Default' -@description('Conditional. The ID(s) to assign to the resource. Required if "cMKKeyName" is not empty.') -param userAssignedIdentities object = {} +@description('Conditional. The managed identity definition for this resource. Required if \'cMKKeyName\' is not empty.') +param managedIdentities managedIdentitiesType @description('Conditional. The resource ID of a key vault to reference a customer managed key for encryption from. Required if "cMKKeyName" is not empty.') param cMKKeyVaultResourceId string = '' @@ -180,11 +180,11 @@ param diagnosticSettings diagnosticSettingType @description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') param enableDefaultTelemetry bool = true -var identityType = !empty(userAssignedIdentities) ? 'UserAssigned' : 'None' +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +var identity = !empty(managedIdentities) ? { + type: !empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } : null var enableReferencedModulesTelemetry = false @@ -378,6 +378,11 @@ output location string = flexibleServer.location // Definitions // // =============== // +type managedIdentitiesType = { + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourcesIds: string[] +}? + type lockType = { @description('Optional. Specify the name of lock.') name: string? diff --git a/modules/db-for-my-sql/flexible-server/main.json b/modules/db-for-my-sql/flexible-server/main.json index a63740f0e8..de8040ea03 100644 --- a/modules/db-for-my-sql/flexible-server/main.json +++ b/modules/db-for-my-sql/flexible-server/main.json @@ -6,13 +6,28 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "13098960413879808793" + "templateHash": "1179455125587700731" }, "name": "DBforMySQL Flexible Servers", "description": "This module deploys a DBforMySQL Flexible Server.", "owner": "Azure/module-maintainers" }, "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourcesIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, "lockType": { "type": "object", "properties": { @@ -322,11 +337,10 @@ "description": "Optional. The mode to create a new MySQL server." } }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Conditional. The ID(s) to assign to the resource. Required if \"cMKKeyName\" is not empty." + "description": "Conditional. The managed identity definition for this resource. Required if 'cMKKeyName' is not empty." } }, "cMKKeyVaultResourceId": { @@ -541,8 +555,8 @@ } }, "variables": { - "identityType": "[if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None')]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", diff --git a/modules/db-for-postgre-sql/flexible-server/.test/public/main.test.bicep b/modules/db-for-postgre-sql/flexible-server/.test/public/main.test.bicep index 1d5c183c98..86320c6f6d 100644 --- a/modules/db-for-postgre-sql/flexible-server/.test/public/main.test.bicep +++ b/modules/db-for-postgre-sql/flexible-server/.test/public/main.test.bicep @@ -135,8 +135,10 @@ module testDeployment '../../main.bicep' = { cMKKeyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId cMKKeyName: nestedDependencies.outputs.keyName cMKUserAssignedIdentityResourceId: nestedDependencies.outputs.managedIdentityResourceId - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/db-for-postgre-sql/flexible-server/README.md b/modules/db-for-postgre-sql/flexible-server/README.md index dad01ed643..2e29c62ecd 100644 --- a/modules/db-for-postgre-sql/flexible-server/README.md +++ b/modules/db-for-postgre-sql/flexible-server/README.md @@ -341,15 +341,17 @@ module flexibleServer 'br:bicep/modules/db-for-postgre-sql.flexible-server:1.0.0 geoRedundantBackup: 'Disabled' highAvailability: 'SameZone' location: '' + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } storageSizeGB: 1024 tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } version: '14' } } @@ -470,6 +472,13 @@ module flexibleServer 'br:bicep/modules/db-for-postgre-sql.flexible-server:1.0.0 "location": { "value": "" }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "storageSizeGB": { "value": 1024 }, @@ -480,11 +489,6 @@ module flexibleServer 'br:bicep/modules/db-for-postgre-sql.flexible-server:1.0.0 "Role": "DeploymentValidation" } }, - "userAssignedIdentities": { - "value": { - "": {} - } - }, "version": { "value": "14" } @@ -512,9 +516,9 @@ module flexibleServer 'br:bicep/modules/db-for-postgre-sql.flexible-server:1.0.0 | :-- | :-- | :-- | | [`cMKKeyVaultResourceId`](#parameter-cmkkeyvaultresourceid) | string | The resource ID of a key vault to reference a customer managed key for encryption from. Required if 'cMKKeyName' is not empty. | | [`cMKUserAssignedIdentityResourceId`](#parameter-cmkuserassignedidentityresourceid) | string | User assigned identity to use when fetching the customer managed key. The identity should have key usage permissions on the Key Vault Key. Required if 'cMKKeyName' is not empty. | +| [`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". | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. Required if 'cMKKeyName' is not empty. | **Optional parameters** @@ -835,6 +839,24 @@ Properties for the maintenence window. If provided, "customWindow" property must - Type: object - Default: `{object}` +### Parameter: `managedIdentities` + +The managed identity definition for this resource. Required if 'cMKKeyName' is not empty. +- 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` The name of the PostgreSQL flexible server. @@ -973,13 +995,6 @@ The tier of the particular SKU. Tier must align with the "skuName" property. Exa - Type: string - Allowed: `[Burstable, GeneralPurpose, MemoryOptimized]` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. Required if 'cMKKeyName' is not empty. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `version` PostgreSQL Server version. diff --git a/modules/db-for-postgre-sql/flexible-server/main.bicep b/modules/db-for-postgre-sql/flexible-server/main.bicep index fe4c7fe3a7..3df7813d86 100644 --- a/modules/db-for-postgre-sql/flexible-server/main.bicep +++ b/modules/db-for-postgre-sql/flexible-server/main.bicep @@ -110,8 +110,8 @@ param highAvailability string = 'Disabled' @description('Optional. The mode to create a new PostgreSQL server.') param createMode string = 'Default' -@description('Conditional. The ID(s) to assign to the resource. Required if \'cMKKeyName\' is not empty.') -param userAssignedIdentities object = {} +@description('Conditional. The managed identity definition for this resource. Required if \'cMKKeyName\' is not empty.') +param managedIdentities managedIdentitiesType @description('Conditional. The resource ID of a key vault to reference a customer managed key for encryption from. Required if \'cMKKeyName\' is not empty.') param cMKKeyVaultResourceId string = '' @@ -164,6 +164,13 @@ param enableDefaultTelemetry bool = true @description('Optional. The diagnostic settings of the service.') param diagnosticSettings diagnosticSettingType +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 + var enableReferencedModulesTelemetry = false var builtInRoleNames = { @@ -203,10 +210,7 @@ resource flexibleServer 'Microsoft.DBforPostgreSQL/flexibleServers@2022-12-01' = name: skuName tier: tier } - identity: { - type: !empty(userAssignedIdentities) ? 'UserAssigned' : 'None' - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : {} - } + identity: identity properties: { administratorLogin: !empty(administratorLogin) ? administratorLogin : null administratorLoginPassword: !empty(administratorLoginPassword) ? administratorLoginPassword : null @@ -365,6 +369,11 @@ output location string = flexibleServer.location // Definitions // // =============== // +type managedIdentitiesType = { + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourcesIds: string[] +}? + type lockType = { @description('Optional. Specify the name of lock.') name: string? diff --git a/modules/db-for-postgre-sql/flexible-server/main.json b/modules/db-for-postgre-sql/flexible-server/main.json index 06684ab38d..fb07682a43 100644 --- a/modules/db-for-postgre-sql/flexible-server/main.json +++ b/modules/db-for-postgre-sql/flexible-server/main.json @@ -6,13 +6,28 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "17360254476628434817" + "templateHash": "2134307033398708647" }, "name": "DBforPostgreSQL Flexible Servers", "description": "This module deploys a DBforPostgreSQL Flexible Server.", "owner": "Azure/module-maintainers" }, "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourcesIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, "lockType": { "type": "object", "properties": { @@ -383,11 +398,10 @@ "description": "Optional. The mode to create a new PostgreSQL server." } }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Conditional. The ID(s) to assign to the resource. Required if 'cMKKeyName' is not empty." + "description": "Conditional. The managed identity definition for this resource. Required if 'cMKKeyName' is not empty." } }, "cMKKeyVaultResourceId": { @@ -508,6 +522,8 @@ } }, "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(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), createObject()))), 'UserAssigned', null()), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", @@ -563,10 +579,7 @@ "name": "[parameters('skuName')]", "tier": "[parameters('tier')]" }, - "identity": { - "type": "[if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None')]", - "userAssignedIdentities": "[if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), createObject())]" - }, + "identity": "[variables('identity')]", "properties": { "administratorLogin": "[if(not(empty(parameters('administratorLogin'))), parameters('administratorLogin'), null())]", "administratorLoginPassword": "[if(not(empty(parameters('administratorLoginPassword'))), parameters('administratorLoginPassword'), null())]", diff --git a/modules/dev-test-lab/lab/.test/common/main.test.bicep b/modules/dev-test-lab/lab/.test/common/main.test.bicep index 41ab747bc6..a6a84a65bf 100644 --- a/modules/dev-test-lab/lab/.test/common/main.test.bicep +++ b/modules/dev-test-lab/lab/.test/common/main.test.bicep @@ -94,12 +94,14 @@ module testDeployment '../../main.bicep' = { enabled: 'Enabled' markdown: 'DevTest Lab support text.
New line. It also supports Markdown' } - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} - } - managementIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } + managementIdentitiesResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] vmCreationResourceGroupId: resourceGroup.id browserConnect: 'Enabled' disableAutoUpgradeCseMinorVersion: true diff --git a/modules/dev-test-lab/lab/README.md b/modules/dev-test-lab/lab/README.md index 2a87c61821..af50afe9e9 100644 --- a/modules/dev-test-lab/lab/README.md +++ b/modules/dev-test-lab/lab/README.md @@ -101,9 +101,14 @@ module lab 'br:bicep/modules/dev-test-lab.lab:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } - managementIdentities: { - '': {} + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] } + managementIdentitiesResourceIds: [ + '' + ] notificationchannels: [ { description: 'Integration configured for auto-shutdown' @@ -234,9 +239,6 @@ module lab 'br:bicep/modules/dev-test-lab.lab:1.0.0' = { labName: 'dtllcom001' resourceType: 'DevTest Lab' } - userAssignedIdentities: { - '': {} - } virtualnetworks: [ { allowedSubnets: [ @@ -373,11 +375,18 @@ module lab 'br:bicep/modules/dev-test-lab.lab:1.0.0' = { "name": "myCustomLockName" } }, - "managementIdentities": { + "managedIdentities": { "value": { - "": {} + "userAssignedResourcesIds": [ + "" + ] } }, + "managementIdentitiesResourceIds": { + "value": [ + "" + ] + }, "notificationchannels": { "value": [ { @@ -522,11 +531,6 @@ module lab 'br:bicep/modules/dev-test-lab.lab:1.0.0' = { "resourceType": "DevTest Lab" } }, - "userAssignedIdentities": { - "value": { - "": {} - } - }, "virtualnetworks": { "value": [ { @@ -655,7 +659,8 @@ module lab 'br:bicep/modules/dev-test-lab.lab:1.0.0' = { | [`labStorageType`](#parameter-labstoragetype) | string | Type of storage used by the lab. It can be either Premium or Standard. | | [`location`](#parameter-location) | string | Location for all Resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | -| [`managementIdentities`](#parameter-managementidentities) | object | The ID(s) to assign to the virtual machines associated with this lab. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | +| [`managementIdentitiesResourceIds`](#parameter-managementidentitiesresourceids) | array | The resource ID(s) to assign to the virtual machines associated with this lab. | | [`mandatoryArtifactsResourceIdsLinux`](#parameter-mandatoryartifactsresourceidslinux) | array | The ordered list of artifact resource IDs that should be applied on all Linux VM creations by default, prior to the artifacts specified by the user. | | [`mandatoryArtifactsResourceIdsWindows`](#parameter-mandatoryartifactsresourceidswindows) | array | The ordered list of artifact resource IDs that should be applied on all Windows VM creations by default, prior to the artifacts specified by the user. | | [`policies`](#parameter-policies) | array | Policies to create for the lab. | @@ -664,7 +669,6 @@ module lab 'br:bicep/modules/dev-test-lab.lab:1.0.0' = { | [`schedules`](#parameter-schedules) | array | Schedules to create for the lab. | | [`support`](#parameter-support) | object | The properties of any lab support message associated with this lab. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`virtualnetworks`](#parameter-virtualnetworks) | array | Virtual networks to create for the lab. | | [`vmCreationResourceGroupId`](#parameter-vmcreationresourcegroupid) | string | Resource Group allocation for virtual machines. If left empty, virtual machines will be deployed in their own Resource Groups. Default is the same Resource Group for DevTest Lab. | @@ -798,12 +802,30 @@ Optional. Specify the name of lock. - Required: No - Type: string -### Parameter: `managementIdentities` +### Parameter: `managedIdentities` -The ID(s) to assign to the virtual machines associated with this lab. +The managed identity definition for this resource. - Required: No - Type: object -- Default: `{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: `managementIdentitiesResourceIds` + +The resource ID(s) to assign to the virtual machines associated with this lab. +- Required: No +- Type: array +- Default: `[]` ### Parameter: `mandatoryArtifactsResourceIdsLinux` @@ -936,13 +958,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `virtualnetworks` Virtual networks to create for the lab. @@ -966,6 +981,7 @@ Resource Group allocation for virtual machines. If left empty, virtual machines | `name` | string | The name of the lab. | | `resourceGroupName` | string | The resource group the lab was deployed into. | | `resourceId` | string | The resource ID of the lab. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | | `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | | `uniqueIdentifier` | string | The unique identifier for the lab. Used to track tags that the lab applies to each resource that it creates. | diff --git a/modules/dev-test-lab/lab/main.bicep b/modules/dev-test-lab/lab/main.bicep index f11bfed17d..2d52f27d29 100644 --- a/modules/dev-test-lab/lab/main.bicep +++ b/modules/dev-test-lab/lab/main.bicep @@ -57,11 +57,11 @@ param premiumDataDisks string = 'Disabled' @description('Optional. The properties of any lab support message associated with this lab.') param support object = {} -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType -@description('Optional. The ID(s) to assign to the virtual machines associated with this lab.') -param managementIdentities object = {} +@description('Optional. The resource ID(s) to assign to the virtual machines associated with this lab.') +param managementIdentitiesResourceIds string[] = [] @description('Optional. Resource Group allocation for virtual machines. If left empty, virtual machines will be deployed in their own Resource Groups. Default is the same Resource Group for DevTest Lab.') param vmCreationResourceGroupId string = resourceGroup().id @@ -116,6 +116,15 @@ param enableDefaultTelemetry bool = true var enableReferencedModulesTelemetry = false +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 ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned' + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null +} : any(null) + +var formattedManagementIdentities = !empty(managementIdentitiesResourceIds) ? reduce(map((managementIdentitiesResourceIds ?? []), (id) => { '${id}': {} }), {}, (cur, next) => union(cur, next)) : {} // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + var builtInRoleNames = { Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') 'DevTest Labs User': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64') @@ -142,10 +151,7 @@ resource lab 'Microsoft.DevTestLab/labs@2018-10-15-preview' = { name: name location: location tags: tags - identity: { - type: !empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned' - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : any(null) - } + identity: identity properties: { artifactsStorageAccount: artifactsStorageAccount announcement: announcement @@ -156,7 +162,7 @@ resource lab 'Microsoft.DevTestLab/labs@2018-10-15-preview' = { mandatoryArtifactsResourceIdsWindows: mandatoryArtifactsResourceIdsWindows premiumDataDisks: premiumDataDisks support: support - managementIdentities: managementIdentities + managementIdentities: formattedManagementIdentities vmCreationResourceGroupId: vmCreationResourceGroupId browserConnect: browserConnect disableAutoUpgradeCseMinorVersion: disableAutoUpgradeCseMinorVersion @@ -312,6 +318,9 @@ output resourceId string = lab.id @description('The name of the lab.') output name string = lab.name +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string = contains(lab.identity, 'principalId') ? lab.identity.principalId : '' + @description('The location the resource was deployed into.') output location string = lab.location @@ -319,6 +328,11 @@ output location string = lab.location // Definitions // // =============== // +type managedIdentitiesType = { + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourcesIds: string[] +}? + type lockType = { @description('Optional. Specify the name of lock.') name: string? diff --git a/modules/dev-test-lab/lab/main.json b/modules/dev-test-lab/lab/main.json index 96178a5f66..0e566cecde 100644 --- a/modules/dev-test-lab/lab/main.json +++ b/modules/dev-test-lab/lab/main.json @@ -6,13 +6,28 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "2990102608284967773" + "templateHash": "15532963443565749928" }, "name": "DevTest Labs", "description": "This module deploys a DevTest Lab.", "owner": "Azure/module-maintainers" }, "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourcesIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, "lockType": { "type": "object", "properties": { @@ -214,18 +229,20 @@ "description": "Optional. The properties of any lab support message associated with this lab." } }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, - "managementIdentities": { - "type": "object", - "defaultValue": {}, + "managementIdentitiesResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], "metadata": { - "description": "Optional. The ID(s) to assign to the virtual machines associated with this lab." + "description": "Optional. The resource ID(s) to assign to the virtual machines associated with this lab." } }, "vmCreationResourceGroupId": { @@ -334,6 +351,9 @@ }, "variables": { "enableReferencedModulesTelemetry": false, + "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()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "formattedManagementIdentities": "[if(not(empty(parameters('managementIdentitiesResourceIds'))), reduce(map(coalesce(parameters('managementIdentitiesResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next')))), createObject())]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", "DevTest Labs User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64')]", @@ -365,10 +385,7 @@ "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", - "identity": { - "type": "[if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned')]", - "userAssignedIdentities": "[if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())]" - }, + "identity": "[variables('identity')]", "properties": { "artifactsStorageAccount": "[parameters('artifactsStorageAccount')]", "announcement": "[parameters('announcement')]", @@ -379,7 +396,7 @@ "mandatoryArtifactsResourceIdsWindows": "[parameters('mandatoryArtifactsResourceIdsWindows')]", "premiumDataDisks": "[parameters('premiumDataDisks')]", "support": "[parameters('support')]", - "managementIdentities": "[parameters('managementIdentities')]", + "managementIdentities": "[variables('formattedManagementIdentities')]", "vmCreationResourceGroupId": "[parameters('vmCreationResourceGroupId')]", "browserConnect": "[parameters('browserConnect')]", "disableAutoUpgradeCseMinorVersion": "[parameters('disableAutoUpgradeCseMinorVersion')]", @@ -1757,6 +1774,13 @@ }, "value": "[parameters('name')]" }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(contains(reference('lab', '2018-10-15-preview', 'full').identity, 'principalId'), reference('lab', '2018-10-15-preview', 'full').identity.principalId, '')]" + }, "location": { "type": "string", "metadata": { diff --git a/modules/document-db/database-account/.test/gremlindb/main.test.bicep b/modules/document-db/database-account/.test/gremlindb/main.test.bicep index 6d53ccd119..f1120061d4 100644 --- a/modules/document-db/database-account/.test/gremlindb/main.test.bicep +++ b/modules/document-db/database-account/.test/gremlindb/main.test.bicep @@ -149,7 +149,9 @@ module testDeployment '../../main.bicep' = { principalType: 'ServicePrincipal' } ] - systemAssignedIdentity: true + managedIdentities: { + systemAssigned: true + } tags: { 'hidden-title': 'This is visible in the resource name' Environment: 'Non-Prod' diff --git a/modules/document-db/database-account/.test/mongodb/main.test.bicep b/modules/document-db/database-account/.test/mongodb/main.test.bicep index a311718a74..e554588b54 100644 --- a/modules/document-db/database-account/.test/mongodb/main.test.bicep +++ b/modules/document-db/database-account/.test/mongodb/main.test.bicep @@ -282,7 +282,9 @@ module testDeployment '../../main.bicep' = { principalType: 'ServicePrincipal' } ] - systemAssignedIdentity: true + managedIdentities: { + systemAssigned: true + } tags: { 'hidden-title': 'This is visible in the resource name' Environment: 'Non-Prod' diff --git a/modules/document-db/database-account/.test/sqldb/main.test.bicep b/modules/document-db/database-account/.test/sqldb/main.test.bicep index 48e552ec3d..2f9254da17 100644 --- a/modules/document-db/database-account/.test/sqldb/main.test.bicep +++ b/modules/document-db/database-account/.test/sqldb/main.test.bicep @@ -189,8 +189,10 @@ module testDeployment '../../main.bicep' = { autoscaleSettingsMaxThroughput: 1000 } ] - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/document-db/database-account/README.md b/modules/document-db/database-account/README.md index e0c384329f..87ab27ddef 100644 --- a/modules/document-db/database-account/README.md +++ b/modules/document-db/database-account/README.md @@ -132,6 +132,9 @@ module databaseAccount 'br:bicep/modules/document-db.database-account:1.0.0' = { } ] location: '' + managedIdentities: { + systemAssigned: true + } roleAssignments: [ { principalId: '' @@ -139,7 +142,6 @@ module databaseAccount 'br:bicep/modules/document-db.database-account:1.0.0' = { roleDefinitionIdOrName: 'Reader' } ] - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -257,6 +259,11 @@ module databaseAccount 'br:bicep/modules/document-db.database-account:1.0.0' = { "location": { "value": "" }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, "roleAssignments": { "value": [ { @@ -266,9 +273,6 @@ module databaseAccount 'br:bicep/modules/document-db.database-account:1.0.0' = { } ] }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", @@ -324,6 +328,9 @@ module databaseAccount 'br:bicep/modules/document-db.database-account:1.0.0' = { ] enableDefaultTelemetry: '' location: '' + managedIdentities: { + systemAssigned: true + } mongodbDatabases: [ { collections: [ @@ -515,7 +522,6 @@ module databaseAccount 'br:bicep/modules/document-db.database-account:1.0.0' = { roleDefinitionIdOrName: 'Reader' } ] - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -578,6 +584,11 @@ module databaseAccount 'br:bicep/modules/document-db.database-account:1.0.0' = { "location": { "value": "" }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, "mongodbDatabases": { "value": [ { @@ -773,9 +784,6 @@ module databaseAccount 'br:bicep/modules/document-db.database-account:1.0.0' = { } ] }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", @@ -970,6 +978,11 @@ module databaseAccount 'br:bicep/modules/document-db.database-account:1.0.0' = { ] enableDefaultTelemetry: '' location: '' + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } privateEndpoints: [ { privateDnsZoneResourceIds: [ @@ -1072,9 +1085,6 @@ module databaseAccount 'br:bicep/modules/document-db.database-account:1.0.0' = { 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -1132,6 +1142,13 @@ module databaseAccount 'br:bicep/modules/document-db.database-account:1.0.0' = { "location": { "value": "" }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "privateEndpoints": { "value": [ { @@ -1241,11 +1258,6 @@ module databaseAccount 'br:bicep/modules/document-db.database-account:1.0.0' = { "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -1283,6 +1295,7 @@ module databaseAccount 'br:bicep/modules/document-db.database-account:1.0.0' = { | [`gremlinDatabases`](#parameter-gremlindatabases) | array | Gremlin Databases configurations. | | [`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. | | [`maxIntervalInSeconds`](#parameter-maxintervalinseconds) | int | Max lag time (minutes). Required for BoundedStaleness. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400. | | [`maxStalenessPrefix`](#parameter-maxstalenessprefix) | int | Max stale requests. Required for BoundedStaleness. Valid ranges, Single Region: 10 to 1000000. Multi Region: 100000 to 1000000. | | [`mongodbDatabases`](#parameter-mongodbdatabases) | array | MongoDB Databases configurations. | @@ -1290,9 +1303,7 @@ module databaseAccount 'br:bicep/modules/document-db.database-account:1.0.0' = { | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalIds' 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'. | | [`serverVersion`](#parameter-serverversion) | string | Specifies the MongoDB server version to use. | | [`sqlDatabases`](#parameter-sqldatabases) | array | SQL Databases configurations. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the Database Account resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | ### Parameter: `automaticFailover` @@ -1539,6 +1550,32 @@ 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: `maxIntervalInSeconds` Max lag time (minutes). Required for BoundedStaleness. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400. @@ -1817,13 +1854,6 @@ SQL Databases configurations. - Type: array - Default: `[]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the Database Account resource. @@ -1831,13 +1861,6 @@ Tags of the Database Account resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs @@ -1847,7 +1870,7 @@ The ID(s) to assign to the resource. | `name` | string | The name of the database account. | | `resourceGroupName` | string | The name of the resource group the database account was created in. | | `resourceId` | string | The resource ID of the database account. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/document-db/database-account/gremlin-database/README.md b/modules/document-db/database-account/gremlin-database/README.md index 4a715c8f19..7436326970 100644 --- a/modules/document-db/database-account/gremlin-database/README.md +++ b/modules/document-db/database-account/gremlin-database/README.md @@ -38,10 +38,8 @@ This module deploys a Gremlin Database within a CosmosDB Account. | [`enableDefaultTelemetry`](#parameter-enabledefaulttelemetry) | bool | Enable telemetry via a Globally Unique Identifier (GUID). | | [`graphs`](#parameter-graphs) | array | Array of graphs to deploy in the Gremlin database. | | [`maxThroughput`](#parameter-maxthroughput) | int | Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the Gremlin database resource. | | [`throughput`](#parameter-throughput) | int | Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | ### Parameter: `databaseAccountName` @@ -76,13 +74,6 @@ Name of the Gremlin database. - Required: Yes - Type: string -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the Gremlin database resource. @@ -97,13 +88,6 @@ Request Units per second (for example 10000). Cannot be set together with `maxTh - Type: int - Default: `-1` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs diff --git a/modules/document-db/database-account/gremlin-database/main.bicep b/modules/document-db/database-account/gremlin-database/main.bicep index 82f0325cbc..bef3ca7288 100644 --- a/modules/document-db/database-account/gremlin-database/main.bicep +++ b/modules/document-db/database-account/gremlin-database/main.bicep @@ -8,12 +8,6 @@ param name string @description('Optional. Tags of the Gremlin database resource.') param tags object = {} -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} - @description('Conditional. The name of the parent Gremlin database. Required if the template is used in a standalone deployment.') param databaseAccountName string @@ -31,8 +25,6 @@ param enableDefaultTelemetry bool = true var enableReferencedModulesTelemetry = false -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') - resource defaultTelemetry 'Microsoft.Resources/deployments@2022-09-01' = if (enableDefaultTelemetry) { name: 'pid-47ed15a6-730a-4827-bcb4-0fd963ffbd82-${uniqueString(deployment().name)}' properties: { @@ -60,10 +52,6 @@ resource gremlinDatabase 'Microsoft.DocumentDB/databaseAccounts/gremlinDatabases name: name tags: tags parent: databaseAccount - identity: (identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null - } : null)! properties: { options: databaseOptions resource: { @@ -92,3 +80,15 @@ output resourceId string = gremlinDatabase.id @description('The name of the resource group the Gremlin database was created in.') output resourceGroupName string = resourceGroup().name + +// =============== // +// 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[]? +}? diff --git a/modules/document-db/database-account/gremlin-database/main.json b/modules/document-db/database-account/gremlin-database/main.json index 3a99fdbe58..aef7829f15 100644 --- a/modules/document-db/database-account/gremlin-database/main.json +++ b/modules/document-db/database-account/gremlin-database/main.json @@ -1,16 +1,42 @@ { "$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.22.6.54827", - "templateHash": "15423165717770718605" + "templateHash": "1439508098279696940" }, "name": "DocumentDB Database Account Gremlin Databases", "description": "This module deploys a Gremlin Database within a CosmosDB Account.", "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 + } + }, "parameters": { "name": { "type": "string", @@ -25,20 +51,6 @@ "description": "Optional. Tags of the Gremlin database resource." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The ID(s) to assign to the resource." - } - }, "databaseAccountName": { "type": "string", "metadata": { @@ -75,11 +87,10 @@ } }, "variables": { - "enableReferencedModulesTelemetry": false, - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]" + "enableReferencedModulesTelemetry": false }, - "resources": [ - { + "resources": { + "defaultTelemetry": { "condition": "[parameters('enableDefaultTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", @@ -93,20 +104,28 @@ } } }, - { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2023-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "gremlinDatabase": { "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", "apiVersion": "2023-04-15", "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", "tags": "[parameters('tags')]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), null())]", "properties": { - "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2023-04-15').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), -1), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', if(not(equals(parameters('throughput'), -1)), parameters('throughput'), null())))]", + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), -1), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', if(not(equals(parameters('throughput'), -1)), parameters('throughput'), null())))]", "resource": { "id": "[parameters('name')]" } - } + }, + "dependsOn": [ + "databaseAccount" + ] }, - { + "gremlinDatabase_gremlinGraphs": { "copy": { "name": "gremlinDatabase_gremlinGraphs", "count": "[length(parameters('graphs'))]" @@ -253,10 +272,10 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" + "gremlinDatabase" ] } - ], + }, "outputs": { "name": { "type": "string", diff --git a/modules/document-db/database-account/main.bicep b/modules/document-db/database-account/main.bicep index ef0e1e141e..3ac93fcc6a 100644 --- a/modules/document-db/database-account/main.bicep +++ b/modules/document-db/database-account/main.bicep @@ -11,11 +11,8 @@ param location string = resourceGroup().location @description('Optional. Tags of the Database Account resource.') param tags object = {} -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. The offer type for the Cosmos DB database account.') @allowed([ @@ -128,11 +125,11 @@ param backupStorageRedundancy string = 'Local' @description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') param privateEndpoints privateEndpointType -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 consistencyPolicy = { @@ -351,7 +348,7 @@ output resourceId string = databaseAccount.id output resourceGroupName string = resourceGroup().name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(databaseAccount.identity, 'principalId') ? databaseAccount.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(databaseAccount.identity, 'principalId') ? databaseAccount.identity.principalId : '' @description('The location the resource was deployed into.') output location string = databaseAccount.location @@ -360,6 +357,14 @@ output location string = databaseAccount.location // 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? diff --git a/modules/document-db/database-account/main.json b/modules/document-db/database-account/main.json index c64588c998..47d04e5c6f 100644 --- a/modules/document-db/database-account/main.json +++ b/modules/document-db/database-account/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "7425318537655406397" + "templateHash": "15206663104495888656" }, "name": "DocumentDB Database Accounts", "description": "This module deploys a DocumentDB Database Account.", "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": { @@ -380,18 +403,10 @@ "description": "Optional. Tags of the Database Account resource." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "databaseAccountOfferType": { @@ -608,8 +623,8 @@ } } ], - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "consistencyPolicy": { "Eventual": { "defaultConsistencyLevel": "Eventual" @@ -1416,17 +1431,43 @@ }, "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.22.6.54827", - "templateHash": "15423165717770718605" + "templateHash": "1439508098279696940" }, "name": "DocumentDB Database Account Gremlin Databases", "description": "This module deploys a Gremlin Database within a CosmosDB Account.", "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 + } + }, "parameters": { "name": { "type": "string", @@ -1441,20 +1482,6 @@ "description": "Optional. Tags of the Gremlin database resource." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The ID(s) to assign to the resource." - } - }, "databaseAccountName": { "type": "string", "metadata": { @@ -1491,11 +1518,10 @@ } }, "variables": { - "enableReferencedModulesTelemetry": false, - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]" + "enableReferencedModulesTelemetry": false }, - "resources": [ - { + "resources": { + "defaultTelemetry": { "condition": "[parameters('enableDefaultTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", @@ -1509,20 +1535,28 @@ } } }, - { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2023-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "gremlinDatabase": { "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", "apiVersion": "2023-04-15", "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", "tags": "[parameters('tags')]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), null())]", "properties": { - "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2023-04-15').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), -1), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', if(not(equals(parameters('throughput'), -1)), parameters('throughput'), null())))]", + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), -1), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', if(not(equals(parameters('throughput'), -1)), parameters('throughput'), null())))]", "resource": { "id": "[parameters('name')]" } - } + }, + "dependsOn": [ + "databaseAccount" + ] }, - { + "gremlinDatabase_gremlinGraphs": { "copy": { "name": "gremlinDatabase_gremlinGraphs", "count": "[length(parameters('graphs'))]" @@ -1669,10 +1703,10 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" + "gremlinDatabase" ] } - ], + }, "outputs": { "name": { "type": "string", @@ -2276,12 +2310,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('databaseAccount', '2023-04-15', 'full').identity, 'principalId')), reference('databaseAccount', '2023-04-15', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('databaseAccount', '2023-04-15', 'full').identity, 'principalId')), reference('databaseAccount', '2023-04-15', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/event-grid/system-topic/.test/common/main.test.bicep b/modules/event-grid/system-topic/.test/common/main.test.bicep index fcd8970f07..72a3551ad0 100644 --- a/modules/event-grid/system-topic/.test/common/main.test.bicep +++ b/modules/event-grid/system-topic/.test/common/main.test.bicep @@ -110,6 +110,9 @@ module testDeployment '../../main.bicep' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + } roleAssignments: [ { roleDefinitionIdOrName: 'Reader' diff --git a/modules/event-grid/system-topic/README.md b/modules/event-grid/system-topic/README.md index 29fe9ed0c9..76aa28f3f5 100644 --- a/modules/event-grid/system-topic/README.md +++ b/modules/event-grid/system-topic/README.md @@ -92,6 +92,9 @@ module systemTopic 'br:bicep/modules/event-grid.system-topic:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + } roleAssignments: [ { principalId: '' @@ -182,6 +185,11 @@ module systemTopic 'br:bicep/modules/event-grid.system-topic:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, "roleAssignments": { "value": [ { @@ -281,10 +289,9 @@ module systemTopic 'br:bicep/modules/event-grid.system-topic:1.0.0' = { | [`eventSubscriptions`](#parameter-eventsubscriptions) | array | Event subscriptions to deploy. | | [`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. | | [`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'. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | ### Parameter: `diagnosticSettings` @@ -449,6 +456,32 @@ 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. @@ -529,13 +562,6 @@ Source for the system topic. - Required: Yes - Type: string -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -549,13 +575,6 @@ TopicType for the system topic. - Required: Yes - Type: string -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs @@ -565,7 +584,7 @@ The ID(s) to assign to the resource. | `name` | string | The name of the event grid system topic. | | `resourceGroupName` | string | The name of the resource group the event grid system topic was deployed into. | | `resourceId` | string | The resource ID of the event grid system topic. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/event-grid/system-topic/main.bicep b/modules/event-grid/system-topic/main.bicep index 32ae0e4226..f851d03ce8 100644 --- a/modules/event-grid/system-topic/main.bicep +++ b/modules/event-grid/system-topic/main.bicep @@ -26,11 +26,8 @@ param roleAssignments roleAssignmentType @description('Optional. The lock settings of the service.') param lock lockType -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. Tags of the resource.') param tags object = {} @@ -38,11 +35,11 @@ param tags object = {} @description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') param enableDefaultTelemetry bool = true -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 = { @@ -159,7 +156,7 @@ output resourceId string = systemTopic.id output resourceGroupName string = resourceGroup().name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(systemTopic.identity, 'principalId') ? systemTopic.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(systemTopic.identity, 'principalId') ? systemTopic.identity.principalId : '' @description('The location the resource was deployed into.') output location string = systemTopic.location @@ -168,6 +165,14 @@ output location string = systemTopic.location // 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? diff --git a/modules/event-grid/system-topic/main.json b/modules/event-grid/system-topic/main.json index cf3f8afd03..6e084c85bd 100644 --- a/modules/event-grid/system-topic/main.json +++ b/modules/event-grid/system-topic/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "5581457669856616058" + "templateHash": "15694608297739544704" }, "name": "Event Grid System Topics", "description": "This module deploys an Event Grid System 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": { @@ -262,18 +285,10 @@ "description": "Optional. The lock settings of the service." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "tags": { @@ -292,8 +307,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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')]", @@ -626,12 +641,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('systemTopic', '2021-12-01', 'full').identity, 'principalId')), reference('systemTopic', '2021-12-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('systemTopic', '2021-12-01', 'full').identity, 'principalId')), reference('systemTopic', '2021-12-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/event-hub/namespace/.test/common/main.test.bicep b/modules/event-hub/namespace/.test/common/main.test.bicep index 3a4cef6289..b276b1734f 100644 --- a/modules/event-hub/namespace/.test/common/main.test.bicep +++ b/modules/event-hub/namespace/.test/common/main.test.bicep @@ -207,9 +207,11 @@ module testDeployment '../../main.bicep' = { principalType: 'ServicePrincipal' } ] - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/event-hub/namespace/.test/encr/main.test.bicep b/modules/event-hub/namespace/.test/encr/main.test.bicep index 39a945d650..ce45fd552e 100644 --- a/modules/event-hub/namespace/.test/encr/main.test.bicep +++ b/modules/event-hub/namespace/.test/encr/main.test.bicep @@ -62,9 +62,11 @@ module testDeployment '../../main.bicep' = { Role: 'DeploymentValidation' } skuName: 'Premium' - systemAssignedIdentity: false - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: false + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } cMKKeyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId cMKKeyName: nestedDependencies.outputs.keyName diff --git a/modules/event-hub/namespace/README.md b/modules/event-hub/namespace/README.md index f7ec816066..01537b304d 100644 --- a/modules/event-hub/namespace/README.md +++ b/modules/event-hub/namespace/README.md @@ -159,6 +159,12 @@ module namespace 'br:bicep/modules/event-hub.namespace:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } maximumThroughputUnits: 4 minimumTlsVersion: '1.2' networkRuleSets: { @@ -201,15 +207,11 @@ module namespace 'br:bicep/modules/event-hub.namespace:1.0.0' = { ] skuCapacity: 2 skuName: 'Standard' - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } zoneRedundant: true } } @@ -351,6 +353,14 @@ module namespace 'br:bicep/modules/event-hub.namespace:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "maximumThroughputUnits": { "value": 4 }, @@ -409,9 +419,6 @@ module namespace 'br:bicep/modules/event-hub.namespace:1.0.0' = { "skuName": { "value": "Standard" }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", @@ -419,11 +426,6 @@ module namespace 'br:bicep/modules/event-hub.namespace:1.0.0' = { "Role": "DeploymentValidation" } }, - "userAssignedIdentities": { - "value": { - "": {} - } - }, "zoneRedundant": { "value": true } @@ -451,18 +453,20 @@ module namespace 'br:bicep/modules/event-hub.namespace:1.0.0' = { cMKKeyVaultResourceId: '' cMKUserAssignedIdentityResourceId: '' enableDefaultTelemetry: '' + managedIdentities: { + systemAssigned: false + userAssignedResourcesIds: [ + '' + ] + } publicNetworkAccess: 'SecuredByPerimeter' requireInfrastructureEncryption: true skuName: 'Premium' - systemAssignedIdentity: false tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -496,6 +500,14 @@ module namespace 'br:bicep/modules/event-hub.namespace:1.0.0' = { "enableDefaultTelemetry": { "value": "" }, + "managedIdentities": { + "value": { + "systemAssigned": false, + "userAssignedResourcesIds": [ + "" + ] + } + }, "publicNetworkAccess": { "value": "SecuredByPerimeter" }, @@ -505,20 +517,12 @@ module namespace 'br:bicep/modules/event-hub.namespace:1.0.0' = { "skuName": { "value": "Premium" }, - "systemAssignedIdentity": { - "value": false - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -704,6 +708,7 @@ module namespace 'br:bicep/modules/event-hub.namespace:1.0.0' = { | [`kafkaEnabled`](#parameter-kafkaenabled) | bool | Value that indicates whether Kafka is enabled for Event Hubs Namespace. | | [`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. | | [`maximumThroughputUnits`](#parameter-maximumthroughputunits) | int | Upper limit of throughput units when AutoInflate is enabled, value should be within 0 to 20 throughput units. | | [`minimumTlsVersion`](#parameter-minimumtlsversion) | string | The minimum TLS version for the cluster to support. | | [`networkRuleSets`](#parameter-networkrulesets) | object | Configure networking options. This object contains IPs/Subnets to allow or restrict access to private endpoints only. For security reasons, it is recommended to configure this object on the Namespace. | @@ -713,9 +718,7 @@ module namespace 'br:bicep/modules/event-hub.namespace:1.0.0' = { | [`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'. | | [`skuCapacity`](#parameter-skucapacity) | int | The Event Hub's throughput units for Basic or Standard tiers, where value should be 0 to 20 throughput units. The Event Hubs premium units for Premium tier, where value should be 0 to 10 premium units. | | [`skuName`](#parameter-skuname) | string | event hub plan SKU name. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`zoneRedundant`](#parameter-zoneredundant) | bool | Switch to make the Event Hub Namespace zone redundant. | ### Parameter: `authorizationRules` @@ -944,6 +947,32 @@ 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: `maximumThroughputUnits` Upper limit of throughput units when AutoInflate is enabled, value should be within 0 to 20 throughput units. @@ -1238,13 +1267,6 @@ event hub plan SKU name. - Default: `'Standard'` - Allowed: `[Basic, Premium, Standard]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -1252,13 +1274,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `zoneRedundant` Switch to make the Event Hub Namespace zone redundant. @@ -1275,7 +1290,7 @@ Switch to make the Event Hub Namespace zone redundant. | `name` | string | The name of the eventspace. | | `resourceGroupName` | string | The resource group where the namespace is deployed. | | `resourceId` | string | The resource ID of the eventspace. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/event-hub/namespace/main.bicep b/modules/event-hub/namespace/main.bicep index 85db737ff3..57097a54ea 100644 --- a/modules/event-hub/namespace/main.bicep +++ b/modules/event-hub/namespace/main.bicep @@ -80,11 +80,8 @@ param diagnosticSettings diagnosticSettingType @description('Optional. The lock settings of the service.') param lock lockType -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. The name of the customer managed key to use for encryption. Customer-managed key encryption at rest is only available for namespaces of premium SKU or namespaces created in a Dedicated Cluster.') param cMKKeyName string = '' @@ -118,11 +115,11 @@ param disasterRecoveryConfig object = {} var maximumThroughputUnitsVar = !isAutoInflateEnabled ? 0 : maximumThroughputUnits -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 enableReferencedModulesTelemetry = false @@ -347,7 +344,7 @@ output resourceId string = eventHubNamespace.id output resourceGroupName string = resourceGroup().name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(eventHubNamespace.identity, 'principalId') ? eventHubNamespace.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(eventHubNamespace.identity, 'principalId') ? eventHubNamespace.identity.principalId : '' @description('The location the resource was deployed into.') output location string = eventHubNamespace.location @@ -356,6 +353,14 @@ output location string = eventHubNamespace.location // 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? diff --git a/modules/event-hub/namespace/main.json b/modules/event-hub/namespace/main.json index d0fd852b27..6e2eb2d442 100644 --- a/modules/event-hub/namespace/main.json +++ b/modules/event-hub/namespace/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "14695132323302557393" + "templateHash": "4102382527672113808" }, "name": "Event Hub Namespaces", "description": "This module deploys an Event Hub Namespace.", "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": { @@ -499,18 +522,10 @@ "description": "Optional. The lock settings of the service." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "cMKKeyName": { @@ -585,8 +600,8 @@ }, "variables": { "maximumThroughputUnitsVar": "[if(not(parameters('isAutoInflateEnabled')), 0, parameters('maximumThroughputUnits'))]", - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Azure Event Hubs Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f526a384-b230-433a-b45c-95f59c4a2dec')]", @@ -2449,12 +2464,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('eventHubNamespace', '2022-10-01-preview', 'full').identity, 'principalId')), reference('eventHubNamespace', '2022-10-01-preview', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('eventHubNamespace', '2022-10-01-preview', 'full').identity, 'principalId')), reference('eventHubNamespace', '2022-10-01-preview', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/health-bot/health-bot/.test/common/main.test.bicep b/modules/health-bot/health-bot/.test/common/main.test.bicep index e75da7bcbc..36623909f7 100644 --- a/modules/health-bot/health-bot/.test/common/main.test.bicep +++ b/modules/health-bot/health-bot/.test/common/main.test.bicep @@ -69,8 +69,10 @@ module testDeployment '../../main.bicep' = { Role: 'DeploymentValidation' } sku: 'F0' - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } } } diff --git a/modules/health-bot/health-bot/README.md b/modules/health-bot/health-bot/README.md index 709308b105..cf5076bc30 100644 --- a/modules/health-bot/health-bot/README.md +++ b/modules/health-bot/health-bot/README.md @@ -51,6 +51,11 @@ module healthBot 'br:bicep/modules/health-bot.health-bot:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } roleAssignments: [ { principalId: '' @@ -63,9 +68,6 @@ module healthBot 'br:bicep/modules/health-bot.health-bot:1.0.0' = { 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -99,6 +101,13 @@ module healthBot 'br:bicep/modules/health-bot.health-bot:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "roleAssignments": { "value": [ { @@ -114,11 +123,6 @@ module healthBot 'br:bicep/modules/health-bot.health-bot:1.0.0' = { "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -196,9 +200,9 @@ module healthBot 'br:bicep/modules/health-bot.health-bot:1.0.0' = { | [`enableDefaultTelemetry`](#parameter-enabledefaulttelemetry) | bool | Enable telemetry via a Globally Unique Identifier (GUID). | | [`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. | | [`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. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | ### Parameter: `enableDefaultTelemetry` @@ -241,6 +245,24 @@ 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 resource. @@ -329,13 +351,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs diff --git a/modules/health-bot/health-bot/main.bicep b/modules/health-bot/health-bot/main.bicep index 5667441e75..c18e4aa195 100644 --- a/modules/health-bot/health-bot/main.bicep +++ b/modules/health-bot/health-bot/main.bicep @@ -13,8 +13,8 @@ param name string @description('Required. The name of the Azure Health Bot SKU.') param sku string -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. Location for all resources.') param location string = resourceGroup().location @@ -31,11 +31,11 @@ param tags object = {} @description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') param enableDefaultTelemetry bool = true -var identityType = !empty(userAssignedIdentities) ? 'UserAssigned' : 'None' +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +var identity = !empty(managedIdentities) ? { + type: !empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } : null var builtInRoleNames = { @@ -108,6 +108,11 @@ output location string = healthBot.location // Definitions // // =============== // +type managedIdentitiesType = { + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourcesIds: string[] +}? + type lockType = { @description('Optional. Specify the name of lock.') name: string? diff --git a/modules/health-bot/health-bot/main.json b/modules/health-bot/health-bot/main.json index 7103f10ea1..f4ee735e27 100644 --- a/modules/health-bot/health-bot/main.json +++ b/modules/health-bot/health-bot/main.json @@ -6,13 +6,28 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "5623490364397811090" + "templateHash": "4815130337915787009" }, "name": "Azure Health Bots", "description": "This module deploys an Azure Health Bot.", "owner": "Azure/module-maintainers" }, "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourcesIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, "lockType": { "type": "object", "properties": { @@ -123,11 +138,10 @@ "description": "Required. The name of the Azure Health Bot SKU." } }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "location": { @@ -165,8 +179,8 @@ } }, "variables": { - "identityType": "[if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None')]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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())]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", diff --git a/modules/healthcare-apis/workspace/.test/common/main.test.bicep b/modules/healthcare-apis/workspace/.test/common/main.test.bicep index 4c8f4d3f7b..fcb3fac8fe 100644 --- a/modules/healthcare-apis/workspace/.test/common/main.test.bicep +++ b/modules/healthcare-apis/workspace/.test/common/main.test.bicep @@ -103,12 +103,14 @@ module testDeployment '../../main.bicep' = { resourceVersionPolicy: 'versioned' smartProxyEnabled: false enableDefaultTelemetry: enableDefaultTelemetry - systemAssignedIdentity: false + managedIdentities: { + systemAssigned: false + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } importEnabled: false initialImportMode: false - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} - } roleAssignments: [ { roleDefinitionIdOrName: resourceId('Microsoft.Authorization/roleDefinitions', '5a1fc7df-4bf1-4951-a576-89034ee01acd') @@ -144,11 +146,12 @@ module testDeployment '../../main.bicep' = { ] publicNetworkAccess: 'Enabled' enableDefaultTelemetry: enableDefaultTelemetry - systemAssignedIdentity: false - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} - } - } + managedIdentities: { + systemAssigned: false + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } } ] roleAssignments: [ { diff --git a/modules/healthcare-apis/workspace/README.md b/modules/healthcare-apis/workspace/README.md index e619b6631f..4db6d1c6c8 100644 --- a/modules/healthcare-apis/workspace/README.md +++ b/modules/healthcare-apis/workspace/README.md @@ -80,12 +80,14 @@ module workspace 'br:bicep/modules/healthcare-apis.workspace:1.0.0' = { ] enableDefaultTelemetry: '' location: '' + managedIdentities: { + systemAssigned: false + userAssignedResourcesIds: [ + '' + ] + } name: 'az-dicom-x-001' publicNetworkAccess: 'Enabled' - systemAssignedIdentity: false - userAssignedIdentities: { - '': {} - } workspaceName: 'hawcom001' } ] @@ -122,6 +124,12 @@ module workspace 'br:bicep/modules/healthcare-apis.workspace:1.0.0' = { initialImportMode: false kind: 'fhir-R4' location: '' + managedIdentities: { + systemAssigned: false + userAssignedResourcesIds: [ + '' + ] + } name: 'az-fhir-x-001' publicNetworkAccess: 'Enabled' resourceVersionPolicy: 'versioned' @@ -133,10 +141,6 @@ module workspace 'br:bicep/modules/healthcare-apis.workspace:1.0.0' = { } ] smartProxyEnabled: false - systemAssignedIdentity: false - userAssignedIdentities: { - '': {} - } workspaceName: 'hawcom001' } ] @@ -209,12 +213,14 @@ module workspace 'br:bicep/modules/healthcare-apis.workspace:1.0.0' = { ], "enableDefaultTelemetry": "", "location": "", + "managedIdentities": { + "systemAssigned": false, + "userAssignedResourcesIds": [ + "" + ] + }, "name": "az-dicom-x-001", "publicNetworkAccess": "Enabled", - "systemAssignedIdentity": false, - "userAssignedIdentities": { - "": {} - }, "workspaceName": "hawcom001" } ] @@ -255,6 +261,12 @@ module workspace 'br:bicep/modules/healthcare-apis.workspace:1.0.0' = { "initialImportMode": false, "kind": "fhir-R4", "location": "", + "managedIdentities": { + "systemAssigned": false, + "userAssignedResourcesIds": [ + "" + ] + }, "name": "az-fhir-x-001", "publicNetworkAccess": "Enabled", "resourceVersionPolicy": "versioned", @@ -266,10 +278,6 @@ module workspace 'br:bicep/modules/healthcare-apis.workspace:1.0.0' = { } ], "smartProxyEnabled": false, - "systemAssignedIdentity": false, - "userAssignedIdentities": { - "": {} - }, "workspaceName": "hawcom001" } ] diff --git a/modules/healthcare-apis/workspace/dicomservice/README.md b/modules/healthcare-apis/workspace/dicomservice/README.md index b1f46574f1..217bc50b8d 100644 --- a/modules/healthcare-apis/workspace/dicomservice/README.md +++ b/modules/healthcare-apis/workspace/dicomservice/README.md @@ -44,10 +44,9 @@ This module deploys a Healthcare API Workspace DICOM Service. | [`enableDefaultTelemetry`](#parameter-enabledefaulttelemetry) | bool | Enable telemetry via the Customer Usage Attribution ID (GUID). | | [`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. | | [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Control permission for data plane traffic coming from public networks while private endpoint is enabled. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | ### Parameter: `corsAllowCredentials` @@ -241,6 +240,32 @@ 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 DICOM service. @@ -255,13 +280,6 @@ Control permission for data plane traffic coming from public networks while priv - Default: `'Disabled'` - Allowed: `[Disabled, Enabled]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -269,13 +287,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `workspaceName` The name of the parent health data services workspace. Required if the template is used in a standalone deployment. @@ -291,7 +302,7 @@ The name of the parent health data services workspace. Required if the template | `name` | string | The name of the dicom service. | | `resourceGroupName` | string | The resource group where the namespace is deployed. | | `resourceId` | string | The resource ID of the dicom service. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/healthcare-apis/workspace/dicomservice/main.bicep b/modules/healthcare-apis/workspace/dicomservice/main.bicep index 8ccdf0334b..29d0dbcf1f 100644 --- a/modules/healthcare-apis/workspace/dicomservice/main.bicep +++ b/modules/healthcare-apis/workspace/dicomservice/main.bicep @@ -48,11 +48,8 @@ param lock lockType @description('Optional. Control permission for data plane traffic coming from public networks while private endpoint is enabled.') param publicNetworkAccess string = 'Disabled' -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. Tags of the resource.') param tags object = {} @@ -60,11 +57,11 @@ param tags object = {} @description('Optional. Enable telemetry via the Customer Usage Attribution ID (GUID).') param enableDefaultTelemetry bool = true -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 // =========== // @@ -149,7 +146,7 @@ output resourceId string = dicom.id output resourceGroupName string = resourceGroup().name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(dicom.identity, 'principalId') ? dicom.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(dicom.identity, 'principalId') ? dicom.identity.principalId : '' @description('The location the resource was deployed into.') output location string = dicom.location @@ -158,6 +155,14 @@ output location string = dicom.location // 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? diff --git a/modules/healthcare-apis/workspace/dicomservice/main.json b/modules/healthcare-apis/workspace/dicomservice/main.json index 2a13e61b2e..f9627046e0 100644 --- a/modules/healthcare-apis/workspace/dicomservice/main.json +++ b/modules/healthcare-apis/workspace/dicomservice/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "2513018044740237283" + "templateHash": "4165874741118763430" }, "name": "Healthcare API Workspace DICOM Services", "description": "This module deploys a Healthcare API Workspace DICOM Service.", "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": { @@ -232,18 +255,10 @@ "description": "Optional. Control permission for data plane traffic coming from public networks while private endpoint is enabled." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "tags": { @@ -262,8 +277,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]" }, "resources": { "defaultTelemetry": { @@ -367,12 +382,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('dicom', '2022-06-01', 'full').identity, 'principalId')), reference('dicom', '2022-06-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('dicom', '2022-06-01', 'full').identity, 'principalId')), reference('dicom', '2022-06-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/healthcare-apis/workspace/fhirservice/README.md b/modules/healthcare-apis/workspace/fhirservice/README.md index 83b67d69e3..9ae8dc574e 100644 --- a/modules/healthcare-apis/workspace/fhirservice/README.md +++ b/modules/healthcare-apis/workspace/fhirservice/README.md @@ -56,14 +56,13 @@ This module deploys a Healthcare API Workspace FHIR Service. | [`kind`](#parameter-kind) | string | The kind of the service. Defaults to R4. | | [`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. | | [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Control permission for data plane traffic coming from public networks while private endpoint is enabled. | | [`resourceVersionOverrides`](#parameter-resourceversionoverrides) | object | A list of FHIR Resources and their version policy overrides. | | [`resourceVersionPolicy`](#parameter-resourceversionpolicy) | string | The default value for tracking history across all resources. | | [`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'. | | [`smartProxyEnabled`](#parameter-smartproxyenabled) | bool | If the SMART on FHIR proxy is enabled. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | ### Parameter: `accessPolicyObjectIds` @@ -328,6 +327,32 @@ 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 FHIR service. @@ -432,13 +457,6 @@ If the SMART on FHIR proxy is enabled. - Type: bool - Default: `False` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -446,13 +464,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `workspaceName` The name of the parent health data services workspace. Required if the template is used in a standalone deployment. @@ -468,7 +479,7 @@ The name of the parent health data services workspace. Required if the template | `name` | string | The name of the fhir service. | | `resourceGroupName` | string | The resource group where the namespace is deployed. | | `resourceId` | string | The resource ID of the fhir service. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | | `workspaceName` | string | The name of the fhir workspace. | ## Cross-referenced modules diff --git a/modules/healthcare-apis/workspace/fhirservice/main.bicep b/modules/healthcare-apis/workspace/fhirservice/main.bicep index 448b59adf0..69c00a4d6a 100644 --- a/modules/healthcare-apis/workspace/fhirservice/main.bicep +++ b/modules/healthcare-apis/workspace/fhirservice/main.bicep @@ -99,11 +99,8 @@ param resourceVersionOverrides object = {} @description('Optional. If the SMART on FHIR proxy is enabled.') param smartProxyEnabled bool = false -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. Tags of the resource.') param tags object = {} @@ -111,11 +108,11 @@ param tags object = {} @description('Optional. Enable telemetry via the Customer Usage Attribution ID (GUID).') param enableDefaultTelemetry bool = true -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 accessPolicies = [for id in accessPolicyObjectIds: { @@ -260,7 +257,7 @@ output resourceId string = fhir.id output resourceGroupName string = resourceGroup().name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(fhir.identity, 'principalId') ? fhir.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(fhir.identity, 'principalId') ? fhir.identity.principalId : '' @description('The location the resource was deployed into.') output location string = fhir.location @@ -272,6 +269,14 @@ output workspaceName string = workspace.name // 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? diff --git a/modules/healthcare-apis/workspace/fhirservice/main.json b/modules/healthcare-apis/workspace/fhirservice/main.json index 40f6f89c72..3b995855d7 100644 --- a/modules/healthcare-apis/workspace/fhirservice/main.json +++ b/modules/healthcare-apis/workspace/fhirservice/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "8392198431844501692" + "templateHash": "14914386228020873144" }, "name": "Healthcare API Workspace FHIR Services", "description": "This module deploys a Healthcare API Workspace FHIR Service.", "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": { @@ -404,18 +427,10 @@ "description": "Optional. If the SMART on FHIR proxy is enabled." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "tags": { @@ -443,8 +458,8 @@ } } ], - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "exportConfiguration": { "storageAccountName": "[parameters('exportStorageAccountName')]" }, @@ -610,12 +625,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('fhir', '2022-06-01', 'full').identity, 'principalId')), reference('fhir', '2022-06-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('fhir', '2022-06-01', 'full').identity, 'principalId')), reference('fhir', '2022-06-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/healthcare-apis/workspace/iotconnector/README.md b/modules/healthcare-apis/workspace/iotconnector/README.md index 45c4d5da83..94f9c1bdf3 100644 --- a/modules/healthcare-apis/workspace/iotconnector/README.md +++ b/modules/healthcare-apis/workspace/iotconnector/README.md @@ -46,9 +46,8 @@ This module deploys a Healthcare API Workspace IoT Connector. | [`fhirdestination`](#parameter-fhirdestination) | object | FHIR Destination. | | [`location`](#parameter-location) | string | Location for all resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | ### Parameter: `consumerGroup` @@ -239,29 +238,41 @@ Optional. Specify the name of lock. - Required: No - Type: string -### Parameter: `name` +### Parameter: `managedIdentities` -The name of the MedTech service. -- Required: Yes -- Type: string +The managed identity definition for this resource. +- Required: No +- Type: object -### Parameter: `systemAssignedIdentity` -Enables system assigned managed identity on the resource. +| 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 -- Default: `False` -### Parameter: `tags` +### Parameter: `managedIdentities.userAssignedResourcesIds` + +Optional. The resource ID(s) to assign to the resource. -Tags of the resource. - Required: No -- Type: object -- Default: `{object}` +- Type: array + +### Parameter: `name` -### Parameter: `userAssignedIdentities` +The name of the MedTech service. +- Required: Yes +- Type: string -The ID(s) to assign to the resource. +### Parameter: `tags` + +Tags of the resource. - Required: No - Type: object - Default: `{object}` @@ -281,7 +292,7 @@ The name of the parent health data services workspace. Required if the template | `name` | string | The name of the medtech service. | | `resourceGroupName` | string | The resource group where the namespace is deployed. | | `resourceId` | string | The resource ID of the medtech service. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | | `workspaceName` | string | The name of the medtech workspace. | ## Cross-referenced modules diff --git a/modules/healthcare-apis/workspace/iotconnector/main.bicep b/modules/healthcare-apis/workspace/iotconnector/main.bicep index 0bba8614b6..c4d2088098 100644 --- a/modules/healthcare-apis/workspace/iotconnector/main.bicep +++ b/modules/healthcare-apis/workspace/iotconnector/main.bicep @@ -36,11 +36,8 @@ param diagnosticSettings diagnosticSettingType @description('Optional. The lock settings of the service.') param lock lockType -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. Tags of the resource.') param tags object = {} @@ -48,11 +45,11 @@ param tags object = {} @description('Optional. Enable telemetry via the Customer Usage Attribution ID (GUID).') param enableDefaultTelemetry bool = true -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 enableReferencedModulesTelemetry = false @@ -156,7 +153,7 @@ output resourceId string = iotConnector.id output resourceGroupName string = resourceGroup().name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(iotConnector.identity, 'principalId') ? iotConnector.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(iotConnector.identity, 'principalId') ? iotConnector.identity.principalId : '' @description('The location the resource was deployed into.') output location string = iotConnector.location @@ -168,6 +165,14 @@ output workspaceName string = workspace.name // 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? diff --git a/modules/healthcare-apis/workspace/iotconnector/main.json b/modules/healthcare-apis/workspace/iotconnector/main.json index 3dd1ccc584..890a2c935e 100644 --- a/modules/healthcare-apis/workspace/iotconnector/main.json +++ b/modules/healthcare-apis/workspace/iotconnector/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "2803151977387469601" + "templateHash": "9502385350114367681" }, "name": "Healthcare API Workspace IoT Connectors", "description": "This module deploys a Healthcare API Workspace IoT Connector.", "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": { @@ -214,18 +237,10 @@ "description": "Optional. The lock settings of the service." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "tags": { @@ -244,8 +259,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "enableReferencedModulesTelemetry": false }, "resources": { @@ -529,12 +544,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('iotConnector', '2022-06-01', 'full').identity, 'principalId')), reference('iotConnector', '2022-06-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('iotConnector', '2022-06-01', 'full').identity, 'principalId')), reference('iotConnector', '2022-06-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/healthcare-apis/workspace/main.bicep b/modules/healthcare-apis/workspace/main.bicep index 6f4af7dae0..60af91948e 100644 --- a/modules/healthcare-apis/workspace/main.bicep +++ b/modules/healthcare-apis/workspace/main.bicep @@ -112,7 +112,7 @@ module workspace_fhirservices 'fhirservice/main.bicep' = [for (fhir, index) in f kind: fhir.kind tags: contains(fhir, 'tags') ? fhir.tags : {} publicNetworkAccess: contains(fhir, 'publicNetworkAccess') ? fhir.publicNetworkAccess : 'Disabled' - systemAssignedIdentity: contains(fhir, 'systemAssignedIdentity') ? fhir.systemAssignedIdentity : false + managedIdentities: contains(fhir, 'managedIdentities') ? fhir.managedIdentities : null roleAssignments: contains(fhir, 'roleAssignments') ? fhir.roleAssignments : [] accessPolicyObjectIds: contains(fhir, 'accessPolicyObjectIds') ? fhir.accessPolicyObjectIds : [] acrLoginServers: contains(fhir, 'acrLoginServers') ? fhir.acrLoginServers : [] @@ -133,7 +133,6 @@ module workspace_fhirservices 'fhirservice/main.bicep' = [for (fhir, index) in f resourceVersionPolicy: contains(fhir, 'resourceVersionPolicy') ? fhir.resourceVersionPolicy : 'versioned' resourceVersionOverrides: contains(fhir, 'resourceVersionOverrides') ? fhir.resourceVersionOverrides : {} smartProxyEnabled: contains(fhir, 'smartProxyEnabled') ? fhir.smartProxyEnabled : false - userAssignedIdentities: contains(fhir, 'userAssignedIdentities') ? fhir.userAssignedIdentities : {} enableDefaultTelemetry: enableReferencedModulesTelemetry } }] @@ -146,7 +145,7 @@ module workspace_dicomservices 'dicomservice/main.bicep' = [for (dicom, index) i workspaceName: workspace.name tags: contains(dicom, 'tags') ? dicom.tags : {} publicNetworkAccess: contains(dicom, 'publicNetworkAccess') ? dicom.publicNetworkAccess : 'Disabled' - systemAssignedIdentity: contains(dicom, 'systemAssignedIdentity') ? dicom.systemAssignedIdentity : false + managedIdentities: contains(dicom, 'managedIdentities') ? dicom.managedIdentities : null corsOrigins: contains(dicom, 'corsOrigins') ? dicom.corsOrigins : [] corsHeaders: contains(dicom, 'corsHeaders') ? dicom.corsHeaders : [] corsMethods: contains(dicom, 'corsMethods') ? dicom.corsMethods : [] @@ -154,7 +153,6 @@ module workspace_dicomservices 'dicomservice/main.bicep' = [for (dicom, index) i corsAllowCredentials: contains(dicom, 'corsAllowCredentials') ? dicom.corsAllowCredentials : false diagnosticSettings: dicom.?diagnosticSettings lock: dicom.?lock ?? lock - userAssignedIdentities: contains(dicom, 'userAssignedIdentities') ? dicom.userAssignedIdentities : {} enableDefaultTelemetry: enableReferencedModulesTelemetry } }] @@ -174,10 +172,9 @@ module workspace_iotconnector 'iotconnector/main.bicep' = [for (iotConnector, in } fhirdestination: contains(iotConnector, 'fhirdestination') ? iotConnector.fhirdestination : {} consumerGroup: contains(iotConnector, 'consumerGroup') ? iotConnector.consumerGroup : iotConnector.name - systemAssignedIdentity: contains(iotConnector, 'systemAssignedIdentity') ? iotConnector.systemAssignedIdentity : false + managedIdentities: contains(iotConnector, 'managedIdentities') ? iotConnector.managedIdentities : null diagnosticSettings: iotConnector.?diagnosticSettings lock: iotConnector.?lock ?? lock - userAssignedIdentities: contains(iotConnector, 'userAssignedIdentities') ? iotConnector.userAssignedIdentities : {} enableDefaultTelemetry: enableReferencedModulesTelemetry } }] diff --git a/modules/healthcare-apis/workspace/main.json b/modules/healthcare-apis/workspace/main.json index 2b5c5ad35c..9954e2db58 100644 --- a/modules/healthcare-apis/workspace/main.json +++ b/modules/healthcare-apis/workspace/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "984819413297046514" + "templateHash": "6558922436832597627" }, "name": "Healthcare API Workspaces", "description": "This module deploys a Healthcare API Workspace.", @@ -287,7 +287,7 @@ }, "tags": "[if(contains(parameters('fhirservices')[copyIndex()], 'tags'), createObject('value', parameters('fhirservices')[copyIndex()].tags), createObject('value', createObject()))]", "publicNetworkAccess": "[if(contains(parameters('fhirservices')[copyIndex()], 'publicNetworkAccess'), createObject('value', parameters('fhirservices')[copyIndex()].publicNetworkAccess), createObject('value', 'Disabled'))]", - "systemAssignedIdentity": "[if(contains(parameters('fhirservices')[copyIndex()], 'systemAssignedIdentity'), createObject('value', parameters('fhirservices')[copyIndex()].systemAssignedIdentity), createObject('value', false()))]", + "managedIdentities": "[if(contains(parameters('fhirservices')[copyIndex()], 'managedIdentities'), createObject('value', parameters('fhirservices')[copyIndex()].managedIdentities), createObject('value', null()))]", "roleAssignments": "[if(contains(parameters('fhirservices')[copyIndex()], 'roleAssignments'), createObject('value', parameters('fhirservices')[copyIndex()].roleAssignments), createObject('value', createArray()))]", "accessPolicyObjectIds": "[if(contains(parameters('fhirservices')[copyIndex()], 'accessPolicyObjectIds'), createObject('value', parameters('fhirservices')[copyIndex()].accessPolicyObjectIds), createObject('value', createArray()))]", "acrLoginServers": "[if(contains(parameters('fhirservices')[copyIndex()], 'acrLoginServers'), createObject('value', parameters('fhirservices')[copyIndex()].acrLoginServers), createObject('value', createArray()))]", @@ -312,7 +312,6 @@ "resourceVersionPolicy": "[if(contains(parameters('fhirservices')[copyIndex()], 'resourceVersionPolicy'), createObject('value', parameters('fhirservices')[copyIndex()].resourceVersionPolicy), createObject('value', 'versioned'))]", "resourceVersionOverrides": "[if(contains(parameters('fhirservices')[copyIndex()], 'resourceVersionOverrides'), createObject('value', parameters('fhirservices')[copyIndex()].resourceVersionOverrides), createObject('value', createObject()))]", "smartProxyEnabled": "[if(contains(parameters('fhirservices')[copyIndex()], 'smartProxyEnabled'), createObject('value', parameters('fhirservices')[copyIndex()].smartProxyEnabled), createObject('value', false()))]", - "userAssignedIdentities": "[if(contains(parameters('fhirservices')[copyIndex()], 'userAssignedIdentities'), createObject('value', parameters('fhirservices')[copyIndex()].userAssignedIdentities), createObject('value', createObject()))]", "enableDefaultTelemetry": { "value": "[variables('enableReferencedModulesTelemetry')]" } @@ -325,13 +324,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "8392198431844501692" + "templateHash": "14914386228020873144" }, "name": "Healthcare API Workspace FHIR Services", "description": "This module deploys a Healthcare API Workspace FHIR Service.", "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": { @@ -723,18 +745,10 @@ "description": "Optional. If the SMART on FHIR proxy is enabled." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "tags": { @@ -762,8 +776,8 @@ } } ], - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "exportConfiguration": { "storageAccountName": "[parameters('exportStorageAccountName')]" }, @@ -929,12 +943,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('fhir', '2022-06-01', 'full').identity, 'principalId')), reference('fhir', '2022-06-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('fhir', '2022-06-01', 'full').identity, 'principalId')), reference('fhir', '2022-06-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", @@ -982,7 +996,7 @@ }, "tags": "[if(contains(parameters('dicomservices')[copyIndex()], 'tags'), createObject('value', parameters('dicomservices')[copyIndex()].tags), createObject('value', createObject()))]", "publicNetworkAccess": "[if(contains(parameters('dicomservices')[copyIndex()], 'publicNetworkAccess'), createObject('value', parameters('dicomservices')[copyIndex()].publicNetworkAccess), createObject('value', 'Disabled'))]", - "systemAssignedIdentity": "[if(contains(parameters('dicomservices')[copyIndex()], 'systemAssignedIdentity'), createObject('value', parameters('dicomservices')[copyIndex()].systemAssignedIdentity), createObject('value', false()))]", + "managedIdentities": "[if(contains(parameters('dicomservices')[copyIndex()], 'managedIdentities'), createObject('value', parameters('dicomservices')[copyIndex()].managedIdentities), createObject('value', null()))]", "corsOrigins": "[if(contains(parameters('dicomservices')[copyIndex()], 'corsOrigins'), createObject('value', parameters('dicomservices')[copyIndex()].corsOrigins), createObject('value', createArray()))]", "corsHeaders": "[if(contains(parameters('dicomservices')[copyIndex()], 'corsHeaders'), createObject('value', parameters('dicomservices')[copyIndex()].corsHeaders), createObject('value', createArray()))]", "corsMethods": "[if(contains(parameters('dicomservices')[copyIndex()], 'corsMethods'), createObject('value', parameters('dicomservices')[copyIndex()].corsMethods), createObject('value', createArray()))]", @@ -994,7 +1008,6 @@ "lock": { "value": "[coalesce(tryGet(parameters('dicomservices')[copyIndex()], 'lock'), parameters('lock'))]" }, - "userAssignedIdentities": "[if(contains(parameters('dicomservices')[copyIndex()], 'userAssignedIdentities'), createObject('value', parameters('dicomservices')[copyIndex()].userAssignedIdentities), createObject('value', createObject()))]", "enableDefaultTelemetry": { "value": "[variables('enableReferencedModulesTelemetry')]" } @@ -1007,13 +1020,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "2513018044740237283" + "templateHash": "4165874741118763430" }, "name": "Healthcare API Workspace DICOM Services", "description": "This module deploys a Healthcare API Workspace DICOM Service.", "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": { @@ -1233,18 +1269,10 @@ "description": "Optional. Control permission for data plane traffic coming from public networks while private endpoint is enabled." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "tags": { @@ -1263,8 +1291,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]" }, "resources": { "defaultTelemetry": { @@ -1368,12 +1396,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('dicom', '2022-06-01', 'full').identity, 'principalId')), reference('dicom', '2022-06-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('dicom', '2022-06-01', 'full').identity, 'principalId')), reference('dicom', '2022-06-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", @@ -1422,14 +1450,13 @@ "deviceMapping": "[if(contains(parameters('iotconnectors')[copyIndex()], 'deviceMapping'), createObject('value', parameters('iotconnectors')[copyIndex()].deviceMapping), createObject('value', createObject('templateType', 'CollectionContent', 'template', createArray())))]", "fhirdestination": "[if(contains(parameters('iotconnectors')[copyIndex()], 'fhirdestination'), createObject('value', parameters('iotconnectors')[copyIndex()].fhirdestination), createObject('value', createObject()))]", "consumerGroup": "[if(contains(parameters('iotconnectors')[copyIndex()], 'consumerGroup'), createObject('value', parameters('iotconnectors')[copyIndex()].consumerGroup), createObject('value', parameters('iotconnectors')[copyIndex()].name))]", - "systemAssignedIdentity": "[if(contains(parameters('iotconnectors')[copyIndex()], 'systemAssignedIdentity'), createObject('value', parameters('iotconnectors')[copyIndex()].systemAssignedIdentity), createObject('value', false()))]", + "managedIdentities": "[if(contains(parameters('iotconnectors')[copyIndex()], 'managedIdentities'), createObject('value', parameters('iotconnectors')[copyIndex()].managedIdentities), createObject('value', null()))]", "diagnosticSettings": { "value": "[tryGet(parameters('iotconnectors')[copyIndex()], 'diagnosticSettings')]" }, "lock": { "value": "[coalesce(tryGet(parameters('iotconnectors')[copyIndex()], 'lock'), parameters('lock'))]" }, - "userAssignedIdentities": "[if(contains(parameters('iotconnectors')[copyIndex()], 'userAssignedIdentities'), createObject('value', parameters('iotconnectors')[copyIndex()].userAssignedIdentities), createObject('value', createObject()))]", "enableDefaultTelemetry": { "value": "[variables('enableReferencedModulesTelemetry')]" } @@ -1442,13 +1469,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "2803151977387469601" + "templateHash": "9502385350114367681" }, "name": "Healthcare API Workspace IoT Connectors", "description": "This module deploys a Healthcare API Workspace IoT Connector.", "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": { @@ -1650,18 +1700,10 @@ "description": "Optional. The lock settings of the service." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "tags": { @@ -1680,8 +1722,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "enableReferencedModulesTelemetry": false }, "resources": { @@ -1965,12 +2007,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('iotConnector', '2022-06-01', 'full').identity, 'principalId')), reference('iotConnector', '2022-06-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('iotConnector', '2022-06-01', 'full').identity, 'principalId')), reference('iotConnector', '2022-06-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/logic/workflow/.test/common/main.test.bicep b/modules/logic/workflow/.test/common/main.test.bicep index bac1970672..f41202d4d8 100644 --- a/modules/logic/workflow/.test/common/main.test.bicep +++ b/modules/logic/workflow/.test/common/main.test.bicep @@ -91,8 +91,10 @@ module testDeployment '../../main.bicep' = { principalType: 'ServicePrincipal' } ] - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/logic/workflow/README.md b/modules/logic/workflow/README.md index ae95fecc20..c1fd8389ad 100644 --- a/modules/logic/workflow/README.md +++ b/modules/logic/workflow/README.md @@ -65,6 +65,11 @@ module workflow 'br:bicep/modules/logic.workflow:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } roleAssignments: [ { principalId: '' @@ -77,9 +82,6 @@ module workflow 'br:bicep/modules/logic.workflow:1.0.0' = { 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } workflowActions: { HTTP: { inputs: { @@ -157,6 +159,13 @@ module workflow 'br:bicep/modules/logic.workflow:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "roleAssignments": { "value": [ { @@ -173,11 +182,6 @@ module workflow 'br:bicep/modules/logic.workflow:1.0.0' = { "Role": "DeploymentValidation" } }, - "userAssignedIdentities": { - "value": { - "": {} - } - }, "workflowActions": { "value": { "HTTP": { @@ -243,12 +247,11 @@ module workflow 'br:bicep/modules/logic.workflow:1.0.0' = { | [`integrationServiceEnvironmentResourceId`](#parameter-integrationserviceenvironmentresourceid) | string | The integration service environment Id. | | [`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'. | | [`state`](#parameter-state) | string | The state. - NotSpecified, Completed, Enabled, Disabled, Deleted, Suspended. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`triggersAccessControlConfiguration`](#parameter-triggersaccesscontrolconfiguration) | object | The access control configuration for invoking workflow triggers. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`workflowActions`](#parameter-workflowactions) | object | The definitions for one or more actions to execute at workflow runtime. | | [`workflowEndpointsConfiguration`](#parameter-workflowendpointsconfiguration) | object | The endpoints configuration: Access endpoint and outgoing IP addresses for the workflow. | | [`workflowManagementAccessControlConfiguration`](#parameter-workflowmanagementaccesscontrolconfiguration) | object | The access control configuration for workflow management. | @@ -455,6 +458,32 @@ Optional. Specify the name of lock. - Required: No - Type: string +### Parameter: `managedIdentities` + +The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both. +- 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 logic app workflow name. @@ -537,13 +566,6 @@ The state. - NotSpecified, Completed, Enabled, Disabled, Deleted, Suspended. - Default: `'Enabled'` - Allowed: `[Completed, Deleted, Disabled, Enabled, NotSpecified, Suspended]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -558,13 +580,6 @@ The access control configuration for invoking workflow triggers. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `workflowActions` The definitions for one or more actions to execute at workflow runtime. @@ -623,7 +638,7 @@ The definitions for one or more triggers that instantiate your workflow. You can | `name` | string | The name of the logic app. | | `resourceGroupName` | string | The resource group the logic app was deployed into. | | `resourceId` | string | The resource ID of the logic app. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/logic/workflow/main.bicep b/modules/logic/workflow/main.bicep index fcd0e6e49c..42d7ede88b 100644 --- a/modules/logic/workflow/main.bicep +++ b/modules/logic/workflow/main.bicep @@ -20,11 +20,8 @@ param enableDefaultTelemetry bool = true @description('Optional. Parameters for the definition template.') param definitionParameters object = {} -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both.') +param managedIdentities managedIdentitiesType @description('Optional. The integration account.') param integrationAccount object = {} @@ -82,11 +79,11 @@ param workflowStaticResults object = {} @description('Optional. The definitions for one or more triggers that instantiate your workflow. You can define more than one trigger, but only with the Workflow Definition Language, not visually through the Logic Apps Designer.') param workflowTriggers object = {} -var identityType = systemAssignedIdentity ? 'SystemAssigned' : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +var identity = !empty(managedIdentities) ? { + type: (managedIdentities.?systemAssigned ?? false) ? 'SystemAssigned' : (!empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null) + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } : null var builtInRoleNames = { @@ -205,7 +202,7 @@ output resourceGroupName string = resourceGroup().name output resourceId string = logicApp.id @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(logicApp.identity, 'principalId') ? logicApp.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(logicApp.identity, 'principalId') ? logicApp.identity.principalId : '' @description('The location the resource was deployed into.') output location string = logicApp.location @@ -214,6 +211,14 @@ output location string = logicApp.location // 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? diff --git a/modules/logic/workflow/main.json b/modules/logic/workflow/main.json index 6842dd2538..fe4b5ccdc9 100644 --- a/modules/logic/workflow/main.json +++ b/modules/logic/workflow/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "6277976941114660068" + "templateHash": "16480420514715732092" }, "name": "Logic Apps (Workflows)", "description": "This module deploys a Logic App (Workflow).", "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": { @@ -253,18 +276,10 @@ "description": "Optional. Parameters for the definition template." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." } }, "integrationAccount": { @@ -386,8 +401,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), 'SystemAssigned', if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), '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')]", "Logic App Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '87a39d53-fc1b-424a-814c-f7e04687dc9e')]", @@ -528,12 +543,12 @@ }, "value": "[resourceId('Microsoft.Logic/workflows', parameters('name'))]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('logicApp', '2019-05-01', 'full').identity, 'principalId')), reference('logicApp', '2019-05-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('logicApp', '2019-05-01', 'full').identity, 'principalId')), reference('logicApp', '2019-05-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/machine-learning-services/workspace/.test/common/main.test.bicep b/modules/machine-learning-services/workspace/.test/common/main.test.bicep index 54219ea277..fa544e14f4 100644 --- a/modules/machine-learning-services/workspace/.test/common/main.test.bicep +++ b/modules/machine-learning-services/workspace/.test/common/main.test.bicep @@ -97,9 +97,11 @@ module testDeployment '../../main.bicep' = { } sku: 'Basic' // Must be false if `primaryUserAssignedIdentity` is provided - systemAssignedIdentity: false - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: false + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } } ] @@ -145,9 +147,11 @@ module testDeployment '../../main.bicep' = { principalType: 'ServicePrincipal' } ] - systemAssignedIdentity: false - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: false + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/machine-learning-services/workspace/.test/encr/main.test.bicep b/modules/machine-learning-services/workspace/.test/encr/main.test.bicep index fcf4a6a6b1..495c4a1b1e 100644 --- a/modules/machine-learning-services/workspace/.test/encr/main.test.bicep +++ b/modules/machine-learning-services/workspace/.test/encr/main.test.bicep @@ -79,10 +79,12 @@ module testDeployment '../../main.bicep' = { } } ] - // Must be false if `primaryUserAssignedIdentity` is provided - systemAssignedIdentity: false - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + // systemAssigned must be false if `primaryUserAssignedIdentity` is provided + managedIdentities: { + systemAssigned: false + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/machine-learning-services/workspace/.test/min/main.test.bicep b/modules/machine-learning-services/workspace/.test/min/main.test.bicep index 8c8e79eeae..94dc5beaab 100644 --- a/modules/machine-learning-services/workspace/.test/min/main.test.bicep +++ b/modules/machine-learning-services/workspace/.test/min/main.test.bicep @@ -58,6 +58,8 @@ module testDeployment '../../main.bicep' = { associatedKeyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId associatedStorageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId sku: 'Basic' - systemAssignedIdentity: true + managedIdentities: { + systemAssigned: true + } } } diff --git a/modules/machine-learning-services/workspace/README.md b/modules/machine-learning-services/workspace/README.md index 606d737fb8..7432a94b53 100644 --- a/modules/machine-learning-services/workspace/README.md +++ b/modules/machine-learning-services/workspace/README.md @@ -62,6 +62,12 @@ module workspace 'br:bicep/modules/machine-learning-services.workspace:1.0.0' = description: 'Default CPU Cluster' disableLocalAuth: false location: 'westeurope' + managedIdentities: { + systemAssigned: false + userAssignedResourcesIds: [ + '' + ] + } name: 'DefaultCPU' properties: { enableNodePublicIp: true @@ -77,10 +83,6 @@ module workspace 'br:bicep/modules/machine-learning-services.workspace:1.0.0' = vmSize: 'STANDARD_DS11_V2' } sku: 'Basic' - systemAssignedIdentity: false - userAssignedIdentities: { - '': {} - } } ] description: 'The cake is a lie.' @@ -105,6 +107,12 @@ module workspace 'br:bicep/modules/machine-learning-services.workspace:1.0.0' = kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: false + userAssignedResourcesIds: [ + '' + ] + } primaryUserAssignedIdentity: '' privateEndpoints: [ { @@ -126,15 +134,11 @@ module workspace 'br:bicep/modules/machine-learning-services.workspace:1.0.0' = roleDefinitionIdOrName: 'Reader' } ] - systemAssignedIdentity: false tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -176,6 +180,12 @@ module workspace 'br:bicep/modules/machine-learning-services.workspace:1.0.0' = "description": "Default CPU Cluster", "disableLocalAuth": false, "location": "westeurope", + "managedIdentities": { + "systemAssigned": false, + "userAssignedResourcesIds": [ + "" + ] + }, "name": "DefaultCPU", "properties": { "enableNodePublicIp": true, @@ -190,11 +200,7 @@ module workspace 'br:bicep/modules/machine-learning-services.workspace:1.0.0' = "vmPriority": "Dedicated", "vmSize": "STANDARD_DS11_V2" }, - "sku": "Basic", - "systemAssignedIdentity": false, - "userAssignedIdentities": { - "": {} - } + "sku": "Basic" } ] }, @@ -232,6 +238,14 @@ module workspace 'br:bicep/modules/machine-learning-services.workspace:1.0.0' = "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": false, + "userAssignedResourcesIds": [ + "" + ] + } + }, "primaryUserAssignedIdentity": { "value": "" }, @@ -259,20 +273,12 @@ module workspace 'br:bicep/modules/machine-learning-services.workspace:1.0.0' = } ] }, - "systemAssignedIdentity": { - "value": false - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -302,6 +308,12 @@ module workspace 'br:bicep/modules/machine-learning-services.workspace:1.0.0' = cMKKeyVaultResourceId: '' cMKUserAssignedIdentityResourceId: '' enableDefaultTelemetry: '' + managedIdentities: { + systemAssigned: false + userAssignedResourcesIds: [ + '' + ] + } primaryUserAssignedIdentity: '' privateEndpoints: [ { @@ -317,15 +329,11 @@ module workspace 'br:bicep/modules/machine-learning-services.workspace:1.0.0' = } } ] - systemAssignedIdentity: false tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -371,6 +379,14 @@ module workspace 'br:bicep/modules/machine-learning-services.workspace:1.0.0' = "enableDefaultTelemetry": { "value": "" }, + "managedIdentities": { + "value": { + "systemAssigned": false, + "userAssignedResourcesIds": [ + "" + ] + } + }, "primaryUserAssignedIdentity": { "value": "" }, @@ -390,20 +406,12 @@ module workspace 'br:bicep/modules/machine-learning-services.workspace:1.0.0' = } ] }, - "systemAssignedIdentity": { - "value": false - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -433,7 +441,9 @@ module workspace 'br:bicep/modules/machine-learning-services.workspace:1.0.0' = sku: 'Basic' // Non-required parameters enableDefaultTelemetry: '' - systemAssignedIdentity: true + managedIdentities: { + systemAssigned: true + } } } ``` @@ -470,8 +480,10 @@ module workspace 'br:bicep/modules/machine-learning-services.workspace:1.0.0' = "enableDefaultTelemetry": { "value": "" }, - "systemAssignedIdentity": { - "value": true + "managedIdentities": { + "value": { + "systemAssigned": true + } } } } @@ -499,8 +511,6 @@ module workspace 'br:bicep/modules/machine-learning-services.workspace:1.0.0' = | :-- | :-- | :-- | | [`cMKKeyVaultResourceId`](#parameter-cmkkeyvaultresourceid) | string | The resource ID of a key vault to reference a customer managed key for encryption from. Required if 'cMKKeyName' is not empty. | | [`primaryUserAssignedIdentity`](#parameter-primaryuserassignedidentity) | string | The user assigned identity resource ID that represents the workspace identity. Required if 'userAssignedIdentities' is not empty and may not be used if 'systemAssignedIdentity' is enabled. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. Required if `userAssignedIdentities` is not provided. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. Required if `systemAssignedIdentity` is set to false. | **Optional parameters** @@ -520,6 +530,7 @@ module workspace 'br:bicep/modules/machine-learning-services.workspace:1.0.0' = | [`imageBuildCompute`](#parameter-imagebuildcompute) | string | The compute name for image build. | | [`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. At least one identity type is required. | | [`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. | | [`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'. | @@ -778,6 +789,32 @@ Optional. Specify the name of lock. - Required: No - Type: string +### Parameter: `managedIdentities` + +The managed identity definition for this resource. At least one identity type is required. +- Required: Yes +- 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 machine learning workspace. @@ -1056,13 +1093,6 @@ Specifies the SKU, also referred as 'edition' of the Azure Machine Learning work - Type: string - Allowed: `[Basic, Free, Premium, Standard]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. Required if `userAssignedIdentities` is not provided. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Resource tags. @@ -1070,13 +1100,6 @@ Resource tags. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. Required if `systemAssignedIdentity` is set to false. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs @@ -1084,9 +1107,9 @@ The ID(s) to assign to the resource. Required if `systemAssignedIdentity` is set | :-- | :-- | :-- | | `location` | string | The location the resource was deployed into. | | `name` | string | The name of the machine learning service. | -| `principalId` | string | The principal ID of the system assigned identity. | | `resourceGroupName` | string | The resource group the machine learning service was deployed into. | | `resourceId` | string | The resource ID of the machine learning service. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/machine-learning-services/workspace/compute/README.md b/modules/machine-learning-services/workspace/compute/README.md index 78fb6a7eee..0e8ebdd101 100644 --- a/modules/machine-learning-services/workspace/compute/README.md +++ b/modules/machine-learning-services/workspace/compute/README.md @@ -42,12 +42,11 @@ Attaching a compute is not idempotent and will fail in case you try to redeploy | [`disableLocalAuth`](#parameter-disablelocalauth) | bool | Opt-out of local authentication and ensure customers can use only MSI and AAD exclusively for authentication. | | [`enableDefaultTelemetry`](#parameter-enabledefaulttelemetry) | bool | Enable telemetry via a Globally Unique Identifier (GUID). | | [`location`](#parameter-location) | string | Specifies the location of the resource. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | | [`properties`](#parameter-properties) | object | The properties of the compute. Will be ignored in case "resourceId" is set. | | [`resourceId`](#parameter-resourceid) | string | ARM resource ID of the underlying compute. | | [`sku`](#parameter-sku) | string | Specifies the sku, also referred as "edition". Required for creating a compute resource. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. Ignored when attaching a compute resource, i.e. when you provide a resource ID. | | [`tags`](#parameter-tags) | object | Contains resource tags defined as key-value pairs. Ignored when attaching a compute resource, i.e. when you provide a resource ID. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. Ignored when attaching a compute resource, i.e. when you provide a resource ID. | ### Parameter: `computeLocation` @@ -104,6 +103,32 @@ The name of the parent Machine Learning Workspace. Required if the template is u - Required: Yes - 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` Name of the compute. @@ -132,13 +157,6 @@ Specifies the sku, also referred as "edition". Required for creating a compute r - Default: `''` - Allowed: `['', Basic, Free, Premium, Standard]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. Ignored when attaching a compute resource, i.e. when you provide a resource ID. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Contains resource tags defined as key-value pairs. Ignored when attaching a compute resource, i.e. when you provide a resource ID. @@ -146,13 +164,6 @@ Contains resource tags defined as key-value pairs. Ignored when attaching a comp - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. Ignored when attaching a compute resource, i.e. when you provide a resource ID. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs @@ -162,7 +173,7 @@ The ID(s) to assign to the resource. Ignored when attaching a compute resource, | `name` | string | The name of the compute. | | `resourceGroupName` | string | The resource group the compute was deployed into. | | `resourceId` | string | The resource ID of the compute. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. Is null in case of attaching a compute resource, i.e. when you provide a resource ID. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/machine-learning-services/workspace/compute/main.bicep b/modules/machine-learning-services/workspace/compute/main.bicep index 9d401399fa..c71f7bc3a0 100644 --- a/modules/machine-learning-services/workspace/compute/main.bicep +++ b/modules/machine-learning-services/workspace/compute/main.bicep @@ -7,6 +7,7 @@ metadata owner = 'Azure/module-maintainers' // ================ // // Parameters // // ================ // + @sys.description('Conditional. The name of the parent Machine Learning Workspace. Required if the template is used in a standalone deployment.') param machineLearningWorkspaceName string @@ -67,26 +68,24 @@ param properties object = {} @sys.description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') param enableDefaultTelemetry bool = true -// Identity -@sys.description('Optional. Enables system assigned managed identity on the resource. Ignored when attaching a compute resource, i.e. when you provide a resource ID.') -param systemAssignedIdentity bool = false - -@sys.description('Optional. The ID(s) to assign to the resource. Ignored when attaching a compute resource, i.e. when you provide a resource ID.') -param userAssignedIdentities object = {} +@sys.description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType // ================// // Variables // // ================// -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') -var identity = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : any(null) -} : any(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: (managedIdentities.?systemAssigned ?? false) ? (!empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null) + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null +} : null // ============================= // // Existing resources references // // ============================= // + resource machineLearningWorkspace 'Microsoft.MachineLearningServices/workspaces@2022-10-01' existing = { name: machineLearningWorkspaceName } @@ -140,8 +139,20 @@ output resourceId string = machineLearningWorkspaceCompute.id @sys.description('The resource group the compute was deployed into.') output resourceGroupName string = resourceGroup().name -@sys.description('The principal ID of the system assigned identity. Is null in case of attaching a compute resource, i.e. when you provide a resource ID.') -output systemAssignedPrincipalId string = empty(resourceId) ? (systemAssignedIdentity && contains(machineLearningWorkspaceCompute.identity, 'principalId') ? machineLearningWorkspaceCompute.identity.principalId : '') : '' +@sys.description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(machineLearningWorkspace.identity, 'principalId') ? machineLearningWorkspace.identity.principalId : '' @sys.description('The location the resource was deployed into.') output location string = machineLearningWorkspaceCompute.location + +// =============== // +// Definitions // +// =============== // + +type managedIdentitiesType = { + @sys.description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? + + @sys.description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourcesIds: string[]? +}? diff --git a/modules/machine-learning-services/workspace/compute/main.json b/modules/machine-learning-services/workspace/compute/main.json index 16e519cbef..c99c3b896e 100644 --- a/modules/machine-learning-services/workspace/compute/main.json +++ b/modules/machine-learning-services/workspace/compute/main.json @@ -1,16 +1,42 @@ { "$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.22.6.54827", - "templateHash": "12652944532720556326" + "templateHash": "12092776287732059217" }, "name": "Machine Learning Services Workspaces Computes", "description": "This module deploys a Machine Learning Services Workspaces Compute.\r\n\r\nAttaching a compute is not idempotent and will fail in case you try to redeploy over an existing compute in AML (see parameter `deployCompute`).", "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 + } + }, "parameters": { "machineLearningWorkspaceName": { "type": "string", @@ -121,27 +147,25 @@ "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource. Ignored when attaching a compute resource, i.e. when you provide a resource ID." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource. Ignored when attaching a compute resource, i.e. when you provide a resource ID." + "description": "Optional. The managed identity definition for this resource." } } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]" }, - "resources": [ - { + "resources": { + "machineLearningWorkspace": { + "existing": true, + "type": "Microsoft.MachineLearningServices/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('machineLearningWorkspaceName')]" + }, + "defaultTelemetry": { "condition": "[parameters('enableDefaultTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2021-04-01", @@ -155,7 +179,7 @@ } } }, - { + "machineLearningWorkspaceCompute": { "condition": "[equals(parameters('deployCompute'), true())]", "type": "Microsoft.MachineLearningServices/workspaces/computes", "apiVersion": "2022-10-01", @@ -164,9 +188,12 @@ "tags": "[if(empty(parameters('resourceId')), parameters('tags'), null())]", "sku": "[if(empty(parameters('resourceId')), createObject('name', parameters('sku'), 'tier', parameters('sku')), null())]", "identity": "[if(empty(parameters('resourceId')), variables('identity'), null())]", - "properties": "[union(createObject('description', parameters('description'), 'disableLocalAuth', parameters('disableLocalAuth'), 'computeType', parameters('computeType')), if(not(empty(parameters('resourceId'))), createObject('resourceId', parameters('resourceId')), createObject('computeLocation', parameters('computeLocation'), 'properties', parameters('properties'))))]" + "properties": "[union(createObject('description', parameters('description'), 'disableLocalAuth', parameters('disableLocalAuth'), 'computeType', parameters('computeType')), if(not(empty(parameters('resourceId'))), createObject('resourceId', parameters('resourceId')), createObject('computeLocation', parameters('computeLocation'), 'properties', parameters('properties'))))]", + "dependsOn": [ + "machineLearningWorkspace" + ] } - ], + }, "outputs": { "name": { "type": "string", @@ -189,19 +216,19 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { - "description": "The principal ID of the system assigned identity. Is null in case of attaching a compute resource, i.e. when you provide a resource ID." + "description": "The principal ID of the system assigned identity." }, - "value": "[if(empty(parameters('resourceId')), if(and(parameters('systemAssignedIdentity'), contains(reference(resourceId('Microsoft.MachineLearningServices/workspaces/computes', parameters('machineLearningWorkspaceName'), parameters('name')), '2022-10-01', 'full').identity, 'principalId')), reference(resourceId('Microsoft.MachineLearningServices/workspaces/computes', parameters('machineLearningWorkspaceName'), parameters('name')), '2022-10-01', 'full').identity.principalId, ''), '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('machineLearningWorkspace', '2022-10-01', 'full').identity, 'principalId')), reference('machineLearningWorkspace', '2022-10-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference(resourceId('Microsoft.MachineLearningServices/workspaces/computes', parameters('machineLearningWorkspaceName'), parameters('name')), '2022-10-01', 'full').location]" + "value": "[reference('machineLearningWorkspaceCompute', '2022-10-01', 'full').location]" } } } \ No newline at end of file diff --git a/modules/machine-learning-services/workspace/main.bicep b/modules/machine-learning-services/workspace/main.bicep index 797ada84d9..b8595ee7a5 100644 --- a/modules/machine-learning-services/workspace/main.bicep +++ b/modules/machine-learning-services/workspace/main.bicep @@ -56,12 +56,10 @@ param tags object = {} @sys.description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') param enableDefaultTelemetry bool = true -// Identity -@sys.description('Conditional. Enables system assigned managed identity on the resource. Required if `userAssignedIdentities` is not provided.') -param systemAssignedIdentity bool = false - -@sys.description('Conditional. The ID(s) to assign to the resource. Required if `systemAssignedIdentity` is set to false.') -param userAssignedIdentities object = {} +@sys.description('Optional. The managed identity definition for this resource. At least one identity type is required.') +param managedIdentities managedIdentitiesType = { + systemAssigned: true +} // Diagnostic Settings @@ -111,12 +109,12 @@ param publicNetworkAccess string = '' // ================// var enableReferencedModulesTelemetry = false -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : any(null) -} : any(null) +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 // ================// // Deployments // @@ -198,8 +196,7 @@ module workspace_computes 'compute/main.bicep' = [for compute in computes: { name: compute.name location: compute.location sku: contains(compute, 'sku') ? compute.sku : '' - systemAssignedIdentity: contains(compute, 'systemAssignedIdentity') ? compute.systemAssignedIdentity : false - userAssignedIdentities: contains(compute, 'userAssignedIdentities') ? compute.userAssignedIdentities : {} + managedIdentities: contains(compute, 'managedIdentities') ? compute.managedIdentities : null tags: contains(compute, 'tags') ? compute.tags : {} deployCompute: contains(compute, 'deployCompute') ? compute.deployCompute : true computeLocation: contains(compute, 'computeLocation') ? compute.computeLocation : '' @@ -301,7 +298,7 @@ output resourceGroupName string = resourceGroup().name output name string = workspace.name @sys.description('The principal ID of the system assigned identity.') -output principalId string = (!empty(identity) && contains(identity.type, 'SystemAssigned')) ? workspace.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(workspace.identity, 'principalId') ? workspace.identity.principalId : '' @sys.description('The location the resource was deployed into.') output location string = workspace.location @@ -310,6 +307,14 @@ output location string = workspace.location // Definitions // // =============== // +type managedIdentitiesType = { + @sys.description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? + + @sys.description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourcesIds: string[]? +} + type lockType = { @sys.description('Optional. Specify the name of lock.') name: string? diff --git a/modules/machine-learning-services/workspace/main.json b/modules/machine-learning-services/workspace/main.json index cd8fde75c5..e136bfc925 100644 --- a/modules/machine-learning-services/workspace/main.json +++ b/modules/machine-learning-services/workspace/main.json @@ -6,13 +6,35 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "9862874616442885683" + "templateHash": "3846104626867448215" }, "name": "Machine Learning Services Workspaces", "description": "This module deploys a Machine Learning Services Workspace.", "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." + } + } + } + }, "lockType": { "type": "object", "properties": { @@ -464,18 +486,13 @@ "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Conditional. Enables system assigned managed identity on the resource. Required if `userAssignedIdentities` is not provided." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "defaultValue": { + "systemAssigned": true + }, "metadata": { - "description": "Conditional. The ID(s) to assign to the resource. Required if `systemAssignedIdentity` is set to false." + "description": "Optional. The managed identity definition for this resource. At least one identity type is required." } }, "diagnosticSettings": { @@ -569,8 +586,8 @@ }, "variables": { "enableReferencedModulesTelemetry": false, - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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": { "AzureML Compute Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e503ece1-11d0-4e8e-8e2c-7a6c3bf38815')]", "AzureML Data Scientist": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f6c7c914-8db3-469d-8ca1-694a8f32e121')]", @@ -734,8 +751,7 @@ "value": "[parameters('computes')[copyIndex()].location]" }, "sku": "[if(contains(parameters('computes')[copyIndex()], 'sku'), createObject('value', parameters('computes')[copyIndex()].sku), createObject('value', ''))]", - "systemAssignedIdentity": "[if(contains(parameters('computes')[copyIndex()], 'systemAssignedIdentity'), createObject('value', parameters('computes')[copyIndex()].systemAssignedIdentity), createObject('value', false()))]", - "userAssignedIdentities": "[if(contains(parameters('computes')[copyIndex()], 'userAssignedIdentities'), createObject('value', parameters('computes')[copyIndex()].userAssignedIdentities), createObject('value', createObject()))]", + "managedIdentities": "[if(contains(parameters('computes')[copyIndex()], 'managedIdentities'), createObject('value', parameters('computes')[copyIndex()].managedIdentities), createObject('value', null()))]", "tags": "[if(contains(parameters('computes')[copyIndex()], 'tags'), createObject('value', parameters('computes')[copyIndex()].tags), createObject('value', createObject()))]", "deployCompute": "[if(contains(parameters('computes')[copyIndex()], 'deployCompute'), createObject('value', parameters('computes')[copyIndex()].deployCompute), createObject('value', true()))]", "computeLocation": "[if(contains(parameters('computes')[copyIndex()], 'computeLocation'), createObject('value', parameters('computes')[copyIndex()].computeLocation), createObject('value', ''))]", @@ -751,17 +767,43 @@ }, "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.22.6.54827", - "templateHash": "12652944532720556326" + "templateHash": "12092776287732059217" }, "name": "Machine Learning Services Workspaces Computes", "description": "This module deploys a Machine Learning Services Workspaces Compute.\r\n\r\nAttaching a compute is not idempotent and will fail in case you try to redeploy over an existing compute in AML (see parameter `deployCompute`).", "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 + } + }, "parameters": { "machineLearningWorkspaceName": { "type": "string", @@ -872,27 +914,25 @@ "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource. Ignored when attaching a compute resource, i.e. when you provide a resource ID." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource. Ignored when attaching a compute resource, i.e. when you provide a resource ID." + "description": "Optional. The managed identity definition for this resource." } } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]" }, - "resources": [ - { + "resources": { + "machineLearningWorkspace": { + "existing": true, + "type": "Microsoft.MachineLearningServices/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('machineLearningWorkspaceName')]" + }, + "defaultTelemetry": { "condition": "[parameters('enableDefaultTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2021-04-01", @@ -906,7 +946,7 @@ } } }, - { + "machineLearningWorkspaceCompute": { "condition": "[equals(parameters('deployCompute'), true())]", "type": "Microsoft.MachineLearningServices/workspaces/computes", "apiVersion": "2022-10-01", @@ -915,9 +955,12 @@ "tags": "[if(empty(parameters('resourceId')), parameters('tags'), null())]", "sku": "[if(empty(parameters('resourceId')), createObject('name', parameters('sku'), 'tier', parameters('sku')), null())]", "identity": "[if(empty(parameters('resourceId')), variables('identity'), null())]", - "properties": "[union(createObject('description', parameters('description'), 'disableLocalAuth', parameters('disableLocalAuth'), 'computeType', parameters('computeType')), if(not(empty(parameters('resourceId'))), createObject('resourceId', parameters('resourceId')), createObject('computeLocation', parameters('computeLocation'), 'properties', parameters('properties'))))]" + "properties": "[union(createObject('description', parameters('description'), 'disableLocalAuth', parameters('disableLocalAuth'), 'computeType', parameters('computeType')), if(not(empty(parameters('resourceId'))), createObject('resourceId', parameters('resourceId')), createObject('computeLocation', parameters('computeLocation'), 'properties', parameters('properties'))))]", + "dependsOn": [ + "machineLearningWorkspace" + ] } - ], + }, "outputs": { "name": { "type": "string", @@ -940,19 +983,19 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { - "description": "The principal ID of the system assigned identity. Is null in case of attaching a compute resource, i.e. when you provide a resource ID." + "description": "The principal ID of the system assigned identity." }, - "value": "[if(empty(parameters('resourceId')), if(and(parameters('systemAssignedIdentity'), contains(reference(resourceId('Microsoft.MachineLearningServices/workspaces/computes', parameters('machineLearningWorkspaceName'), parameters('name')), '2022-10-01', 'full').identity, 'principalId')), reference(resourceId('Microsoft.MachineLearningServices/workspaces/computes', parameters('machineLearningWorkspaceName'), parameters('name')), '2022-10-01', 'full').identity.principalId, ''), '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('machineLearningWorkspace', '2022-10-01', 'full').identity, 'principalId')), reference('machineLearningWorkspace', '2022-10-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference(resourceId('Microsoft.MachineLearningServices/workspaces/computes', parameters('machineLearningWorkspaceName'), parameters('name')), '2022-10-01', 'full').location]" + "value": "[reference('machineLearningWorkspaceCompute', '2022-10-01', 'full').location]" } } } @@ -1536,12 +1579,12 @@ }, "value": "[parameters('name')]" }, - "principalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(not(empty(variables('identity'))), contains(variables('identity').type, 'SystemAssigned')), reference('workspace', '2022-10-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('workspace', '2022-10-01', 'full').identity, 'principalId')), reference('workspace', '2022-10-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/net-app/net-app-account/.test/nfs41/main.test.bicep b/modules/net-app/net-app-account/.test/nfs41/main.test.bicep index c80906d8fd..c58995a201 100644 --- a/modules/net-app/net-app-account/.test/nfs41/main.test.bicep +++ b/modules/net-app/net-app-account/.test/nfs41/main.test.bicep @@ -138,8 +138,10 @@ module testDeployment '../../main.bicep' = { Role: 'DeploymentValidation' ServiceName: 'DeploymentValidation' } - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } } } diff --git a/modules/net-app/net-app-account/README.md b/modules/net-app/net-app-account/README.md index 8f0db1332a..38a316bf45 100644 --- a/modules/net-app/net-app-account/README.md +++ b/modules/net-app/net-app-account/README.md @@ -383,6 +383,11 @@ module netAppAccount 'br:bicep/modules/net-app.net-app-account:1.0.0' = { } ] enableDefaultTelemetry: '' + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } roleAssignments: [ { principalId: '' @@ -399,9 +404,6 @@ module netAppAccount 'br:bicep/modules/net-app.net-app-account:1.0.0' = { Role: 'DeploymentValidation' ServiceName: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -500,6 +502,13 @@ module netAppAccount 'br:bicep/modules/net-app.net-app-account:1.0.0' = { "enableDefaultTelemetry": { "value": "" }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "roleAssignments": { "value": [ { @@ -519,11 +528,6 @@ module netAppAccount 'br:bicep/modules/net-app.net-app-account:1.0.0' = { "Role": "DeploymentValidation", "ServiceName": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -554,10 +558,10 @@ module netAppAccount 'br:bicep/modules/net-app.net-app-account:1.0.0' = { | [`enableDefaultTelemetry`](#parameter-enabledefaulttelemetry) | bool | Enable telemetry via a Globally Unique Identifier (GUID). | | [`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. | | [`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'. | | [`smbServerNamePrefix`](#parameter-smbservernameprefix) | string | Required if domainName is specified. NetBIOS name of the SMB server. A computer account with this prefix will be registered in the AD and used to mount volumes. | | [`tags`](#parameter-tags) | object | Tags for all resources. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | ### Parameter: `capacityPools` @@ -642,6 +646,24 @@ 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` The name of the NetApp account. @@ -730,13 +752,6 @@ Tags for all resources. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs diff --git a/modules/net-app/net-app-account/main.bicep b/modules/net-app/net-app-account/main.bicep index 92f867153d..ffd5558bf5 100644 --- a/modules/net-app/net-app-account/main.bicep +++ b/modules/net-app/net-app-account/main.bicep @@ -27,8 +27,8 @@ param smbServerNamePrefix string = '' @description('Optional. Capacity pools to create.') param capacityPools array = [] -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @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 @@ -58,11 +58,11 @@ var activeDirectoryConnectionProperties = [ } ] -var identityType = !empty(userAssignedIdentities) ? 'UserAssigned' : 'None' +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +var identity = !empty(managedIdentities) ? { + type: !empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } : null var builtInRoleNames = { @@ -152,6 +152,11 @@ output location string = netAppAccount.location // Definitions // // =============== // +type managedIdentitiesType = { + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourcesIds: string[] +}? + type lockType = { @description('Optional. Specify the name of lock.') name: string? diff --git a/modules/net-app/net-app-account/main.json b/modules/net-app/net-app-account/main.json index 72636832be..bba591714a 100644 --- a/modules/net-app/net-app-account/main.json +++ b/modules/net-app/net-app-account/main.json @@ -6,13 +6,28 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "6454914933986539170" + "templateHash": "17236803464512744934" }, "name": "Azure NetApp Files", "description": "This module deploys an Azure NetApp File.", "owner": "Azure/module-maintainers" }, "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourcesIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, "lockType": { "type": "object", "properties": { @@ -161,11 +176,10 @@ "description": "Optional. Capacity pools to create." } }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "roleAssignments": { @@ -214,8 +228,8 @@ "organizationalUnit": "[if(not(empty(parameters('domainJoinOU'))), parameters('domainJoinOU'), null())]" } ], - "identityType": "[if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None')]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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())]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", diff --git a/modules/network/application-gateway/.test/common/main.test.bicep b/modules/network/application-gateway/.test/common/main.test.bicep index dd833556e4..8f81d6033f 100644 --- a/modules/network/application-gateway/.test/common/main.test.bicep +++ b/modules/network/application-gateway/.test/common/main.test.bicep @@ -430,8 +430,10 @@ module testDeployment '../../main.bicep' = { } } ] - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } rewriteRuleSets: [ { diff --git a/modules/network/application-gateway/README.md b/modules/network/application-gateway/README.md index bea07ec10b..88340aa660 100644 --- a/modules/network/application-gateway/README.md +++ b/modules/network/application-gateway/README.md @@ -238,6 +238,11 @@ module applicationGateway 'br:bicep/modules/network.application-gateway:1.0.0' = kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } privateEndpoints: [ { privateDnsZoneResourceIds: [ @@ -438,9 +443,6 @@ module applicationGateway 'br:bicep/modules/network.application-gateway:1.0.0' = 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } webApplicationFirewallConfiguration: { disabledRuleGroups: [ { @@ -700,6 +702,13 @@ module applicationGateway 'br:bicep/modules/network.application-gateway:1.0.0' = "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "privateEndpoints": { "value": [ { @@ -920,11 +929,6 @@ module applicationGateway 'br:bicep/modules/network.application-gateway:1.0.0' = "Role": "DeploymentValidation" } }, - "userAssignedIdentities": { - "value": { - "": {} - } - }, "webApplicationFirewallConfiguration": { "value": { "disabledRuleGroups": [ @@ -997,6 +1001,7 @@ module applicationGateway 'br:bicep/modules/network.application-gateway:1.0.0' = | [`loadDistributionPolicies`](#parameter-loaddistributionpolicies) | array | Load distribution policies of the application gateway resource. | | [`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. | | [`privateLinkConfigurations`](#parameter-privatelinkconfigurations) | array | PrivateLink configurations on application gateway. | | [`probes`](#parameter-probes) | array | Probes of the application gateway resource. | @@ -1016,7 +1021,6 @@ module applicationGateway 'br:bicep/modules/network.application-gateway:1.0.0' = | [`trustedClientCertificates`](#parameter-trustedclientcertificates) | array | Trusted client certificates of the application gateway resource. | | [`trustedRootCertificates`](#parameter-trustedrootcertificates) | array | Trusted Root certificates of the application gateway resource. | | [`urlPathMaps`](#parameter-urlpathmaps) | array | URL path map of the application gateway resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`webApplicationFirewallConfiguration`](#parameter-webapplicationfirewallconfiguration) | object | Application gateway web application firewall configuration. Should be configured for security reasons. | | [`zones`](#parameter-zones) | array | A list of availability zones denoting where the resource needs to come from. | @@ -1309,6 +1313,24 @@ 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 Application Gateway. @@ -1675,13 +1697,6 @@ URL path map of the application gateway resource. - Type: array - Default: `[]` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `webApplicationFirewallConfiguration` Application gateway web application firewall configuration. Should be configured for security reasons. diff --git a/modules/network/application-gateway/main.bicep b/modules/network/application-gateway/main.bicep index 98595f165f..32ab52f5e2 100644 --- a/modules/network/application-gateway/main.bicep +++ b/modules/network/application-gateway/main.bicep @@ -9,8 +9,8 @@ param name string @description('Optional. Location for all resources.') param location string = resourceGroup().location -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. Authentication certificates of the application gateway resource.') param authenticationCertificates array = [] @@ -183,11 +183,11 @@ param zones array = [] @description('Optional. The diagnostic settings of the service.') param diagnosticSettings diagnosticSettingType -var identityType = !empty(userAssignedIdentities) ? 'UserAssigned' : 'None' +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +var identity = !empty(managedIdentities) ? { + type: !empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } : null var enableReferencedModulesTelemetry = false @@ -385,6 +385,11 @@ output location string = applicationGateway.location // Definitions // // =============== // +type managedIdentitiesType = { + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourcesIds: string[] +}? + type lockType = { @description('Optional. Specify the name of lock.') name: string? diff --git a/modules/network/application-gateway/main.json b/modules/network/application-gateway/main.json index 7103d784b0..60170cfa02 100644 --- a/modules/network/application-gateway/main.json +++ b/modules/network/application-gateway/main.json @@ -6,13 +6,28 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "1471682538744123689" + "templateHash": "9820071049711446778" }, "name": "Network Application Gateways", "description": "This module deploys a Network Application Gateway.", "owner": "Azure/module-maintainers" }, "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourcesIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, "lockType": { "type": "object", "properties": { @@ -374,11 +389,10 @@ "description": "Optional. Location for all resources." } }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "authenticationCertificates": { @@ -743,8 +757,8 @@ } }, "variables": { - "identityType": "[if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None')]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", diff --git a/modules/network/firewall-policy/README.md b/modules/network/firewall-policy/README.md index 6c127c21e5..4e48c3b55c 100644 --- a/modules/network/firewall-policy/README.md +++ b/modules/network/firewall-policy/README.md @@ -248,6 +248,7 @@ module firewallPolicy 'br:bicep/modules/network.firewall-policy:1.0.0' = { | [`ipAddresses`](#parameter-ipaddresses) | array | List of IP addresses for the ThreatIntel Allowlist. | | [`keyVaultSecretId`](#parameter-keyvaultsecretid) | string | Secret ID of (base-64 encoded unencrypted PFX) Secret or Certificate object stored in KeyVault. | | [`location`](#parameter-location) | string | Location for all resources. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | | [`mode`](#parameter-mode) | string | The configuring of intrusion detection. | | [`privateRanges`](#parameter-privateranges) | array | List of private IP addresses/IP address ranges to not be SNAT. | | [`retentionDays`](#parameter-retentiondays) | int | Number of days the insights should be enabled on the policy. | @@ -257,7 +258,6 @@ module firewallPolicy 'br:bicep/modules/network.firewall-policy:1.0.0' = { | [`tags`](#parameter-tags) | object | Tags of the Firewall policy resource. | | [`threatIntelMode`](#parameter-threatintelmode) | string | The operation mode for Threat Intel. | | [`tier`](#parameter-tier) | string | Tier of Firewall Policy. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`workspaces`](#parameter-workspaces) | array | List of workspaces for Firewall Policy Insights. | ### Parameter: `allowSqlRedirect` @@ -352,6 +352,24 @@ Location for all resources. - Type: string - Default: `[resourceGroup().location]` +### 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: `mode` The configuring of intrusion detection. @@ -424,13 +442,6 @@ Tier of Firewall Policy. - Default: `'Standard'` - Allowed: `[Premium, Standard]` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `workspaces` List of workspaces for Firewall Policy Insights. diff --git a/modules/network/firewall-policy/main.bicep b/modules/network/firewall-policy/main.bicep index 13da1d1af1..6c4a638446 100644 --- a/modules/network/firewall-policy/main.bicep +++ b/modules/network/firewall-policy/main.bicep @@ -11,8 +11,8 @@ param location string = resourceGroup().location @description('Optional. Tags of the Firewall policy resource.') param tags object = {} -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. Resource ID of the base policy.') param basePolicyResourceId string = '' @@ -96,11 +96,11 @@ param enableDefaultTelemetry bool = true @description('Optional. Rule collection groups.') param ruleCollectionGroups array = [] -var identityType = !empty(userAssignedIdentities) ? 'UserAssigned' : 'None' +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +var identity = !empty(managedIdentities) ? { + type: !empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } : null var enableReferencedModulesTelemetry = false @@ -198,3 +198,12 @@ output resourceGroupName string = resourceGroup().name @description('The location the resource was deployed into.') output location string = firewallPolicy.location + +// =============== // +// Definitions // +// =============== // + +type managedIdentitiesType = { + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourcesIds: string[] +}? diff --git a/modules/network/firewall-policy/main.json b/modules/network/firewall-policy/main.json index 466fff08d7..aa93b198e2 100644 --- a/modules/network/firewall-policy/main.json +++ b/modules/network/firewall-policy/main.json @@ -1,16 +1,34 @@ { "$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.22.6.54827", - "templateHash": "18116522930721554549" + "templateHash": "411576668957997252" }, "name": "Firewall Policies", "description": "This module deploys a Firewall Policy.", "owner": "Azure/module-maintainers" }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourcesIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + } + }, "parameters": { "name": { "type": "string", @@ -32,11 +50,10 @@ "description": "Optional. Tags of the Firewall policy resource." } }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "basePolicyResourceId": { @@ -206,12 +223,12 @@ } }, "variables": { - "identityType": "[if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None')]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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())]", "enableReferencedModulesTelemetry": false }, - "resources": [ - { + "resources": { + "defaultTelemetry": { "condition": "[parameters('enableDefaultTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2021-04-01", @@ -225,7 +242,7 @@ } } }, - { + "firewallPolicy": { "type": "Microsoft.Network/firewallPolicies", "apiVersion": "2023-04-01", "name": "[parameters('name')]", @@ -252,7 +269,7 @@ "transportSecurity": "[if(or(not(empty(parameters('keyVaultSecretId'))), not(empty(parameters('certificateName')))), createObject('certificateAuthority', createObject('keyVaultSecretId', if(not(empty(parameters('keyVaultSecretId'))), parameters('keyVaultSecretId'), null()), 'name', if(not(empty(parameters('certificateName'))), parameters('certificateName'), null()))), null())]" } }, - { + "firewallPolicy_ruleCollectionGroups": { "copy": { "name": "firewallPolicy_ruleCollectionGroups", "count": "[length(parameters('ruleCollectionGroups'))]", @@ -382,10 +399,10 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Network/firewallPolicies', parameters('name'))]" + "firewallPolicy" ] } - ], + }, "outputs": { "name": { "type": "string", @@ -413,7 +430,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference(resourceId('Microsoft.Network/firewallPolicies', parameters('name')), '2023-04-01', 'full').location]" + "value": "[reference('firewallPolicy', '2023-04-01', 'full').location]" } } } \ No newline at end of file diff --git a/modules/operational-insights/workspace/.test/adv/main.test.bicep b/modules/operational-insights/workspace/.test/adv/main.test.bicep index e5050aabd4..268d776147 100644 --- a/modules/operational-insights/workspace/.test/adv/main.test.bicep +++ b/modules/operational-insights/workspace/.test/adv/main.test.bicep @@ -295,8 +295,10 @@ module testDeployment '../../main.bicep' = { ] } ] - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/operational-insights/workspace/.test/common/main.test.bicep b/modules/operational-insights/workspace/.test/common/main.test.bicep index e965cb4bcb..607cbbae50 100644 --- a/modules/operational-insights/workspace/.test/common/main.test.bicep +++ b/modules/operational-insights/workspace/.test/common/main.test.bicep @@ -223,7 +223,9 @@ module testDeployment '../../main.bicep' = { Environment: 'Non-Prod' Role: 'DeploymentValidation' } - systemAssignedIdentity: true + managedIdentities: { + systemAssigned: true + } roleAssignments: [ { roleDefinitionIdOrName: 'Reader' diff --git a/modules/operational-insights/workspace/README.md b/modules/operational-insights/workspace/README.md index 4975d90de3..7a39d99942 100644 --- a/modules/operational-insights/workspace/README.md +++ b/modules/operational-insights/workspace/README.md @@ -207,6 +207,11 @@ module workspace 'br:bicep/modules/operational-insights.workspace:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } publicNetworkAccessForIngestion: 'Disabled' publicNetworkAccessForQuery: 'Disabled' savedSearches: [ @@ -285,9 +290,6 @@ module workspace 'br:bicep/modules/operational-insights.workspace:1.0.0' = { 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } useResourcePermissions: true } } @@ -483,6 +485,13 @@ module workspace 'br:bicep/modules/operational-insights.workspace:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "publicNetworkAccessForIngestion": { "value": "Disabled" }, @@ -573,11 +582,6 @@ module workspace 'br:bicep/modules/operational-insights.workspace:1.0.0' = { "Role": "DeploymentValidation" } }, - "userAssignedIdentities": { - "value": { - "": {} - } - }, "useResourcePermissions": { "value": true } @@ -733,6 +737,9 @@ module workspace 'br:bicep/modules/operational-insights.workspace:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + } publicNetworkAccessForIngestion: 'Disabled' publicNetworkAccessForQuery: 'Disabled' roleAssignments: [ @@ -761,7 +768,6 @@ module workspace 'br:bicep/modules/operational-insights.workspace:1.0.0' = { ] } ] - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -934,6 +940,11 @@ module workspace 'br:bicep/modules/operational-insights.workspace:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, "publicNetworkAccessForIngestion": { "value": "Disabled" }, @@ -972,9 +983,6 @@ module workspace 'br:bicep/modules/operational-insights.workspace:1.0.0' = { } ] }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", @@ -1070,6 +1078,7 @@ module workspace 'br:bicep/modules/operational-insights.workspace:1.0.0' = { | [`linkedServices`](#parameter-linkedservices) | array | List of services to be linked. | | [`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. | | [`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'. | @@ -1077,10 +1086,8 @@ module workspace 'br:bicep/modules/operational-insights.workspace:1.0.0' = { | [`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. | | [`storageInsightsConfigs`](#parameter-storageinsightsconfigs) | array | List of storage accounts to be read by the workspace. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tables`](#parameter-tables) | array | LAW custom tables to be deployed. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`useResourcePermissions`](#parameter-useresourcepermissions) | bool | Set to 'true' to use resource or workspace permissions and 'false' (or leave empty) to require workspace permissions. | ### Parameter: `dailyQuotaGb` @@ -1295,6 +1302,32 @@ Optional. Specify the name of lock. - Required: No - Type: string +### Parameter: `managedIdentities` + +The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both. +- 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` Name of the Log Analytics workspace. @@ -1414,13 +1447,6 @@ List of storage accounts to be read by the workspace. - Type: array - Default: `[]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tables` LAW custom tables to be deployed. @@ -1435,13 +1461,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `useResourcePermissions` Set to 'true' to use resource or workspace permissions and 'false' (or leave empty) to require workspace permissions. @@ -1459,7 +1478,7 @@ Set to 'true' to use resource or workspace permissions and 'false' (or leave emp | `name` | string | The name of the deployed log analytics workspace. | | `resourceGroupName` | string | The resource group of the deployed log analytics workspace. | | `resourceId` | string | The resource ID of the deployed log analytics workspace. | -| `systemAssignedIdentityPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/operational-insights/workspace/main.bicep b/modules/operational-insights/workspace/main.bicep index 687b0c94bf..6220a5deb5 100644 --- a/modules/operational-insights/workspace/main.bicep +++ b/modules/operational-insights/workspace/main.bicep @@ -73,11 +73,8 @@ param publicNetworkAccessForIngestion string = 'Enabled' ]) param publicNetworkAccessForQuery string = 'Enabled' -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both.') +param managedIdentities managedIdentitiesType @description('Optional. Set to \'true\' to use resource or workspace permissions and \'false\' (or leave empty) to require workspace permissions.') param useResourcePermissions bool = false @@ -102,11 +99,11 @@ param enableDefaultTelemetry bool = true var enableReferencedModulesTelemetry = false -var identityType = systemAssignedIdentity ? 'SystemAssigned' : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +var identity = !empty(managedIdentities) ? { + type: (managedIdentities.?systemAssigned ?? false) ? 'SystemAssigned' : (!empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null) + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } : null var builtInRoleNames = { @@ -335,12 +332,20 @@ output logAnalyticsWorkspaceId string = logAnalyticsWorkspace.properties.custome output location string = logAnalyticsWorkspace.location @description('The principal ID of the system assigned identity.') -output systemAssignedIdentityPrincipalId string = systemAssignedIdentity && contains(logAnalyticsWorkspace.identity, 'principalId') ? logAnalyticsWorkspace.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(logAnalyticsWorkspace.identity, 'principalId') ? logAnalyticsWorkspace.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? diff --git a/modules/operational-insights/workspace/main.json b/modules/operational-insights/workspace/main.json index 3bc1884eea..19df45d446 100644 --- a/modules/operational-insights/workspace/main.json +++ b/modules/operational-insights/workspace/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "535028874764214077" + "templateHash": "12796424281221754385" }, "name": "Log Analytics Workspaces", "description": "This module deploys a Log Analytics Workspace.", "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": { @@ -346,18 +369,10 @@ "description": "Optional. The network access type for accessing Log Analytics query." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." } }, "useResourcePermissions": { @@ -409,8 +424,8 @@ }, "variables": { "enableReferencedModulesTelemetry": false, - "identityType": "[if(parameters('systemAssignedIdentity'), 'SystemAssigned', if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), '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')]", "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", @@ -1862,12 +1877,12 @@ }, "value": "[reference('logAnalyticsWorkspace', '2022-10-01', 'full').location]" }, - "systemAssignedIdentityPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('logAnalyticsWorkspace', '2022-10-01', 'full').identity, 'principalId')), reference('logAnalyticsWorkspace', '2022-10-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('logAnalyticsWorkspace', '2022-10-01', 'full').identity, 'principalId')), reference('logAnalyticsWorkspace', '2022-10-01', 'full').identity.principalId, '')]" } } } \ No newline at end of file diff --git a/modules/purview/account/.test/common/main.test.bicep b/modules/purview/account/.test/common/main.test.bicep index 162aa96a6b..5dfc03d500 100644 --- a/modules/purview/account/.test/common/main.test.bicep +++ b/modules/purview/account/.test/common/main.test.bicep @@ -72,8 +72,10 @@ module testDeployment '../../main.bicep' = { Environment: 'Non-Prod' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } managedResourceGroupName: '${namePrefix}${serviceShort}001-managed-rg' publicNetworkAccess: 'Disabled' diff --git a/modules/purview/account/README.md b/modules/purview/account/README.md index be248ec0f3..152f7ba851 100644 --- a/modules/purview/account/README.md +++ b/modules/purview/account/README.md @@ -96,6 +96,11 @@ module account 'br:bicep/modules/purview.account:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } managedResourceGroupName: 'pvacom001-managed-rg' portalPrivateEndpoints: [ { @@ -152,9 +157,6 @@ module account 'br:bicep/modules/purview.account:1.0.0' = { 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -236,6 +238,13 @@ module account 'br:bicep/modules/purview.account:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "managedResourceGroupName": { "value": "pvacom001-managed-rg" }, @@ -305,11 +314,6 @@ module account 'br:bicep/modules/purview.account:1.0.0' = { "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -389,6 +393,7 @@ module account 'br:bicep/modules/purview.account:1.0.0' = { | [`eventHubPrivateEndpoints`](#parameter-eventhubprivateendpoints) | array | Configuration details for Purview Managed Event Hub namespace private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Make sure the service property is set to 'namespace'. | | [`location`](#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. | | [`managedResourceGroupName`](#parameter-managedresourcegroupname) | string | The Managed Resource Group Name. A managed Storage Account, and an Event Hubs will be created in the selected subscription for catalog ingestion scenarios. Default is 'managed-rg-'. | | [`portalPrivateEndpoints`](#parameter-portalprivateendpoints) | array | Configuration details for Purview Portal private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Make sure the service property is set to 'portal'. | | [`publicNetworkAccess`](#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. | @@ -396,7 +401,6 @@ module account 'br:bicep/modules/purview.account:1.0.0' = { | [`storageBlobPrivateEndpoints`](#parameter-storageblobprivateendpoints) | array | Configuration details for Purview Managed Storage Account blob private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Make sure the service property is set to 'blob'. | | [`storageQueuePrivateEndpoints`](#parameter-storagequeueprivateendpoints) | array | Configuration details for Purview Managed Storage Account queue private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Make sure the service property is set to 'queue'. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | ### Parameter: `accountPrivateEndpoints` @@ -568,6 +572,24 @@ 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: `managedResourceGroupName` The Managed Resource Group Name. A managed Storage Account, and an Event Hubs will be created in the selected subscription for catalog ingestion scenarios. Default is 'managed-rg-'. @@ -685,13 +707,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs @@ -705,7 +720,7 @@ The ID(s) to assign to the resource. | `name` | string | The name of the Purview Account. | | `resourceGroupName` | string | The resource group the Purview Account was deployed into. | | `resourceId` | string | The resource ID of the Purview Account. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/purview/account/main.bicep b/modules/purview/account/main.bicep index ad6ce7da95..8410915c30 100644 --- a/modules/purview/account/main.bicep +++ b/modules/purview/account/main.bicep @@ -13,8 +13,8 @@ param location string = resourceGroup().location @description('Optional. Tags of the resource.') param tags object = {} -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. The Managed Resource Group Name. A managed Storage Account, and an Event Hubs will be created in the selected subscription for catalog ingestion scenarios. Default is \'managed-rg-\'.') param managedResourceGroupName string = 'managed-rg-${name}' @@ -58,12 +58,12 @@ param lock lockType // Variables // // =========== // -var identityType = !empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned' +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null -} : null +var identity = { + type: !empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned' + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null +} var enableReferencedModulesTelemetry = false @@ -91,7 +91,7 @@ resource account 'Microsoft.Purview/accounts@2021-07-01' = { name: name location: location tags: tags - identity: any(identity) + identity: identity properties: { cloudConnectors: {} managedResourceGroupName: managedResourceGroupName @@ -293,12 +293,17 @@ output managedStorageAccountId string = account.properties.managedResources.stor output managedEventHubId string = account.properties.managedResources.eventHubNamespace @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = account.identity.principalId +output systemAssignedMIPrincipalId string = contains(account.identity, 'principalId') ? account.identity.principalId : '' // =============== // // Definitions // // =============== // +type managedIdentitiesType = { + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourcesIds: string[] +}? + type lockType = { @description('Optional. Specify the name of lock.') name: string? diff --git a/modules/purview/account/main.json b/modules/purview/account/main.json index d76b19e9d5..47a49e254a 100644 --- a/modules/purview/account/main.json +++ b/modules/purview/account/main.json @@ -6,13 +6,28 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "13668353398980769357" + "templateHash": "18408981482699771035" }, "name": "Purview Accounts", "description": "This module deploys a Purview Account.", "owner": "Azure/module-maintainers" }, "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourcesIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, "lockType": { "type": "object", "properties": { @@ -234,11 +249,10 @@ "description": "Optional. Tags of the resource." } }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "managedResourceGroupName": { @@ -322,8 +336,11 @@ } }, "variables": { - "identityType": "[if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned')]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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": { + "type": "[if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned')]", + "userAssignedIdentities": "[if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())]" + }, "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", @@ -3133,12 +3150,12 @@ }, "value": "[reference('account').managedResources.eventHubNamespace]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[reference('account', '2021-07-01', 'full').identity.principalId]" + "value": "[if(contains(reference('account', '2021-07-01', 'full').identity, 'principalId'), reference('account', '2021-07-01', 'full').identity.principalId, '')]" } } } \ No newline at end of file diff --git a/modules/recovery-services/vault/.test/common/main.test.bicep b/modules/recovery-services/vault/.test/common/main.test.bicep index 942b0c01bf..81d25194c7 100644 --- a/modules/recovery-services/vault/.test/common/main.test.bicep +++ b/modules/recovery-services/vault/.test/common/main.test.bicep @@ -330,6 +330,12 @@ module testDeployment '../../main.bicep' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } privateEndpoints: [ { privateDnsZoneResourceIds: [ diff --git a/modules/recovery-services/vault/README.md b/modules/recovery-services/vault/README.md index b30ccb22f9..5258daf120 100644 --- a/modules/recovery-services/vault/README.md +++ b/modules/recovery-services/vault/README.md @@ -316,6 +316,12 @@ module vault 'br:bicep/modules/recovery-services.vault:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } monitoringSettings: { azureMonitorAlertSettings: { alertsForAllJobFailures: 'Enabled' @@ -651,6 +657,14 @@ module vault 'br:bicep/modules/recovery-services.vault:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "monitoringSettings": { "value": { "azureMonitorAlertSettings": { @@ -954,6 +968,7 @@ module vault 'br:bicep/modules/recovery-services.vault:1.0.0' = { | [`enableDefaultTelemetry`](#parameter-enabledefaulttelemetry) | bool | Enable telemetry via a Globally Unique Identifier (GUID). | | [`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. | | [`monitoringSettings`](#parameter-monitoringsettings) | object | Monitoring Settings of the vault. | | [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | | [`protectionContainers`](#parameter-protectioncontainers) | array | List of all protection containers. | @@ -963,9 +978,7 @@ module vault 'br:bicep/modules/recovery-services.vault:1.0.0' = { | [`replicationPolicies`](#parameter-replicationpolicies) | array | List of all replication policies. | | [`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'. | | [`securitySettings`](#parameter-securitysettings) | object | Security Settings of the vault. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the Recovery Service Vault resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | ### Parameter: `backupConfig` @@ -1144,6 +1157,32 @@ 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: `monitoringSettings` Monitoring Settings of the vault. @@ -1436,13 +1475,6 @@ Security Settings of the vault. - Type: object - Default: `{object}` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the Recovery Service Vault resource. @@ -1450,13 +1482,6 @@ Tags of the Recovery Service Vault resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs @@ -1466,7 +1491,7 @@ The ID(s) to assign to the resource. | `name` | string | The Name of the recovery services vault. | | `resourceGroupName` | string | The name of the resource group the recovery services vault was created in. | | `resourceId` | string | The resource ID of the recovery services vault. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/recovery-services/vault/main.bicep b/modules/recovery-services/vault/main.bicep index 708723f4f4..623b3ddad7 100644 --- a/modules/recovery-services/vault/main.bicep +++ b/modules/recovery-services/vault/main.bicep @@ -44,11 +44,8 @@ param roleAssignments roleAssignmentType @description('Optional. The lock settings of the service.') param lock lockType -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. Tags of the Recovery Service Vault resource.') param tags object = {} @@ -69,11 +66,11 @@ param securitySettings object = {} ]) param publicNetworkAccess string = 'Disabled' -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 enableReferencedModulesTelemetry = false @@ -293,7 +290,7 @@ output resourceGroupName string = resourceGroup().name output name string = rsv.name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(rsv.identity, 'principalId') ? rsv.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(rsv.identity, 'principalId') ? rsv.identity.principalId : '' @description('The location the resource was deployed into.') output location string = rsv.location @@ -302,6 +299,14 @@ output location string = rsv.location // 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? diff --git a/modules/recovery-services/vault/main.json b/modules/recovery-services/vault/main.json index 6fddf5168d..db634c5922 100644 --- a/modules/recovery-services/vault/main.json +++ b/modules/recovery-services/vault/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "15528544750404538266" + "templateHash": "18413268993568593224" }, "name": "Recovery Services Vaults", "description": "This module deploys a Recovery Services Vault.", "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": { @@ -451,18 +474,10 @@ "description": "Optional. The lock settings of the service." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "tags": { @@ -505,8 +520,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e467623-bb1f-42f4-a55d-6e525e11384b')]", @@ -2741,12 +2756,12 @@ }, "value": "[parameters('name')]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('rsv', '2023-01-01', 'full').identity, 'principalId')), reference('rsv', '2023-01-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('rsv', '2023-01-01', 'full').identity, 'principalId')), reference('rsv', '2023-01-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/resources/deployment-script/.test/cli/main.test.bicep b/modules/resources/deployment-script/.test/cli/main.test.bicep index 9c2194b2cc..6f72c40370 100644 --- a/modules/resources/deployment-script/.test/cli/main.test.bicep +++ b/modules/resources/deployment-script/.test/cli/main.test.bicep @@ -58,8 +58,10 @@ module testDeployment '../../main.bicep' = { scriptContent: 'echo \'echo echo echo\'' storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId timeout: 'PT30M' - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/resources/deployment-script/.test/ps/main.test.bicep b/modules/resources/deployment-script/.test/ps/main.test.bicep index 00cea68eaf..96ae61a018 100644 --- a/modules/resources/deployment-script/.test/ps/main.test.bicep +++ b/modules/resources/deployment-script/.test/ps/main.test.bicep @@ -62,8 +62,10 @@ module testDeployment '../../main.bicep' = { scriptContent: 'Write-Host \'The cake is a lie!\'' storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId timeout: 'PT30M' - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/resources/deployment-script/README.md b/modules/resources/deployment-script/README.md index 35e3486eb6..2d19703a31 100644 --- a/modules/resources/deployment-script/README.md +++ b/modules/resources/deployment-script/README.md @@ -57,6 +57,11 @@ module deploymentScript 'br:bicep/modules/resources.deployment-script:1.0.0' = { ] } kind: 'AzureCLI' + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } retentionInterval: 'P1D' runOnce: false scriptContent: 'echo \'echo echo echo\'' @@ -67,9 +72,6 @@ module deploymentScript 'br:bicep/modules/resources.deployment-script:1.0.0' = { Role: 'DeploymentValidation' } timeout: 'PT30M' - userAssignedIdentities: { - '': {} - } } } ``` @@ -117,6 +119,13 @@ module deploymentScript 'br:bicep/modules/resources.deployment-script:1.0.0' = { "kind": { "value": "AzureCLI" }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "retentionInterval": { "value": "P1D" }, @@ -138,11 +147,6 @@ module deploymentScript 'br:bicep/modules/resources.deployment-script:1.0.0' = { }, "timeout": { "value": "PT30M" - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -172,6 +176,11 @@ module deploymentScript 'br:bicep/modules/resources.deployment-script:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + userAssignedResourcesIds: [ + '' + ] + } retentionInterval: 'P1D' runOnce: false scriptContent: 'Write-Host \'The cake is a lie!\'' @@ -182,9 +191,6 @@ module deploymentScript 'br:bicep/modules/resources.deployment-script:1.0.0' = { Role: 'DeploymentValidation' } timeout: 'PT30M' - userAssignedIdentities: { - '': {} - } } } ``` @@ -224,6 +230,13 @@ module deploymentScript 'br:bicep/modules/resources.deployment-script:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "" + ] + } + }, "retentionInterval": { "value": "P1D" }, @@ -245,11 +258,6 @@ module deploymentScript 'br:bicep/modules/resources.deployment-script:1.0.0' = { }, "timeout": { "value": "PT30M" - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -281,6 +289,7 @@ module deploymentScript 'br:bicep/modules/resources.deployment-script:1.0.0' = { | [`kind`](#parameter-kind) | string | Type of the script. AzurePowerShell, AzureCLI. | | [`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). | | [`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. | @@ -289,7 +298,6 @@ module deploymentScript 'br:bicep/modules/resources.deployment-script:1.0.0' = { | [`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 | Tags of the resource. | | [`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. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | **Generated parameters** @@ -396,6 +404,24 @@ 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` Display name of the script to be run. @@ -458,13 +484,6 @@ Maximum allowed script execution time specified in ISO 8601 format. Default valu - Type: string - Default: `'PT1H'` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs diff --git a/modules/resources/deployment-script/main.bicep b/modules/resources/deployment-script/main.bicep index f596af33f9..4e1f4c7062 100644 --- a/modules/resources/deployment-script/main.bicep +++ b/modules/resources/deployment-script/main.bicep @@ -5,8 +5,8 @@ metadata owner = 'Azure/module-maintainers' @description('Required. Display name of the script to be run.') param name string -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. Location for all resources.') param location string = resourceGroup().location @@ -79,11 +79,11 @@ var containerSettings = { containerGroupName: containerGroupName } -var identityType = !empty(userAssignedIdentities) ? 'UserAssigned' : 'None' +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +var identity = !empty(managedIdentities) ? { + type: !empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } : null var storageAccountSettings = !empty(storageAccountResourceId) ? { @@ -154,6 +154,11 @@ output outputs object = contains(deploymentScript.properties, 'outputs') ? deplo // Definitions // // =============== // +type managedIdentitiesType = { + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourcesIds: string[] +}? + type lockType = { @description('Optional. Specify the name of lock.') name: string? diff --git a/modules/resources/deployment-script/main.json b/modules/resources/deployment-script/main.json index fc7ac9db4a..d2af767dcd 100644 --- a/modules/resources/deployment-script/main.json +++ b/modules/resources/deployment-script/main.json @@ -6,13 +6,28 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "2858511394966028740" + "templateHash": "10287022408270224079" }, "name": "Deployment Scripts", "description": "This module deploys a Deployment Script.", "owner": "Azure/module-maintainers" }, "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourcesIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, "lockType": { "type": "object", "properties": { @@ -46,11 +61,10 @@ "description": "Required. Display name of the script to be run." } }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "location": { @@ -199,8 +213,8 @@ "containerSettings": { "containerGroupName": "[parameters('containerGroupName')]" }, - "identityType": "[if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None')]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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": { "defaultTelemetry": { diff --git a/modules/search/search-service/.test/common/main.test.bicep b/modules/search/search-service/.test/common/main.test.bicep index 69b3722a94..1190190f6e 100644 --- a/modules/search/search-service/.test/common/main.test.bicep +++ b/modules/search/search-service/.test/common/main.test.bicep @@ -77,7 +77,9 @@ module testDeployment '../../main.bicep' = { hostingMode: 'highDensity' partitionCount: 2 replicaCount: 3 - systemAssignedIdentity: true + managedIdentities: { + systemAssigned: true + } lock: { kind: 'CanNotDelete' name: 'myCustomLockName' diff --git a/modules/search/search-service/README.md b/modules/search/search-service/README.md index 268380a6de..e116efe345 100644 --- a/modules/search/search-service/README.md +++ b/modules/search/search-service/README.md @@ -77,6 +77,9 @@ module searchService 'br:bicep/modules/search.search-service:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + } networkRuleSet: { ipRules: [ { @@ -102,7 +105,6 @@ module searchService 'br:bicep/modules/search.search-service:1.0.0' = { } ] sku: 'standard3' - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -170,6 +172,11 @@ module searchService 'br:bicep/modules/search.search-service:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, "networkRuleSet": { "value": { "ipRules": [ @@ -205,9 +212,6 @@ module searchService 'br:bicep/modules/search.search-service:1.0.0' = { "sku": { "value": "standard3" }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", @@ -412,6 +416,7 @@ module searchService 'br:bicep/modules/search.search-service:1.0.0' = { | [`hostingMode`](#parameter-hostingmode) | string | Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'. | | [`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. | | [`networkRuleSet`](#parameter-networkruleset) | object | Network specific rules that determine how the Azure Cognitive Search service may be reached. | | [`partitionCount`](#parameter-partitioncount) | int | The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3. | | [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | @@ -420,7 +425,6 @@ module searchService 'br:bicep/modules/search.search-service:1.0.0' = { | [`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'. | | [`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. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags to help categorize the resource in the Azure portal. | ### Parameter: `authOptions` @@ -609,6 +613,24 @@ 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. | + +### Parameter: `managedIdentities.systemAssigned` + +Optional. Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + ### Parameter: `name` The name of the Azure Cognitive Search service to create or update. Search service names must only contain lowercase letters, digits or dashes, cannot use dash as the first two or last one characters, cannot contain consecutive dashes, and must be between 2 and 60 characters in length. Search service names must be globally unique since they are part of the service URI (https://.search.windows.net). You cannot change the service name after the service is created. @@ -895,13 +917,6 @@ Defines the SKU of an Azure Cognitive Search Service, which determines price tie - Default: `'standard'` - Allowed: `[basic, free, standard, standard2, standard3, storage_optimized_l1, storage_optimized_l2]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags to help categorize the resource in the Azure portal. @@ -918,6 +933,7 @@ Tags to help categorize the resource in the Azure portal. | `name` | string | The name of the search service. | | `resourceGroupName` | string | The name of the resource group the search service was created in. | | `resourceId` | string | The resource ID of the search service. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/search/search-service/main.bicep b/modules/search/search-service/main.bicep index 063f199ee2..5597e7b853 100644 --- a/modules/search/search-service/main.bicep +++ b/modules/search/search-service/main.bicep @@ -80,8 +80,8 @@ param roleAssignments roleAssignmentType ]) param sku string = 'standard' -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. The diagnostic settings of the service.') param diagnosticSettings diagnosticSettingType @@ -95,10 +95,8 @@ param tags object = {} var enableReferencedModulesTelemetry = false -var identityType = systemAssignedIdentity ? 'SystemAssigned' : 'None' - -var identity = identityType != 'None' ? { - type: identityType +var identity = !empty(managedIdentities) ? { + type: (managedIdentities.?systemAssigned ?? false) ? 'SystemAssigned' : null } : null // =============== // @@ -253,6 +251,9 @@ output resourceId string = searchService.id @description('The name of the resource group the search service was created in.') output resourceGroupName string = resourceGroup().name +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(searchService.identity, 'principalId') ? searchService.identity.principalId : '' + @description('The location the resource was deployed into.') output location string = searchService.location @@ -260,6 +261,11 @@ output location string = searchService.location // Definitions // // =============== // +type managedIdentitiesType = { + @description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? +}? + type lockType = { @description('Optional. Specify the name of lock.') name: string? diff --git a/modules/search/search-service/main.json b/modules/search/search-service/main.json index c40e5596be..b7467ad1f0 100644 --- a/modules/search/search-service/main.json +++ b/modules/search/search-service/main.json @@ -6,13 +6,26 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "416393199352439530" + "templateHash": "6839264843077014016" }, "name": "Search Services", "description": "This module deploys a Search Service.", "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." + } + } + }, + "nullable": true + }, "lockType": { "type": "object", "properties": { @@ -495,11 +508,10 @@ "description": "Optional. Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." + "description": "Optional. The managed identity definition for this resource." } }, "diagnosticSettings": { @@ -518,8 +530,7 @@ }, "variables": { "enableReferencedModulesTelemetry": false, - "identityType": "[if(parameters('systemAssignedIdentity'), 'SystemAssigned', 'None')]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType')), null())]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", @@ -1347,6 +1358,13 @@ }, "value": "[resourceGroup().name]" }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('searchService', '2022-09-01', 'full').identity, 'principalId')), reference('searchService', '2022-09-01', 'full').identity.principalId, '')]" + }, "location": { "type": "string", "metadata": { diff --git a/modules/service-bus/namespace/.test/common/main.test.bicep b/modules/service-bus/namespace/.test/common/main.test.bicep index 02fee0b4ea..b5f4fed0fa 100644 --- a/modules/service-bus/namespace/.test/common/main.test.bicep +++ b/modules/service-bus/namespace/.test/common/main.test.bicep @@ -213,9 +213,11 @@ module testDeployment '../../main.bicep' = { } } ] - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } disableLocalAuth: true publicNetworkAccess: 'Enabled' diff --git a/modules/service-bus/namespace/.test/encr/main.test.bicep b/modules/service-bus/namespace/.test/encr/main.test.bicep index c88e244f39..e1f3da9f89 100644 --- a/modules/service-bus/namespace/.test/encr/main.test.bicep +++ b/modules/service-bus/namespace/.test/encr/main.test.bicep @@ -100,9 +100,11 @@ module testDeployment '../../main.bicep' = { ] } ] - systemAssignedIdentity: false - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: false + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } cMKKeyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId cMKKeyName: nestedDependencies.outputs.keyName diff --git a/modules/service-bus/namespace/README.md b/modules/service-bus/namespace/README.md index 13de5e2461..877ff238b5 100644 --- a/modules/service-bus/namespace/README.md +++ b/modules/service-bus/namespace/README.md @@ -95,6 +95,12 @@ module namespace 'br:bicep/modules/service-bus.namespace:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } minimumTlsVersion: '1.2' networkRuleSets: { defaultAction: 'Deny' @@ -172,7 +178,6 @@ module namespace 'br:bicep/modules/service-bus.namespace:1.0.0' = { ] skuCapacity: 2 skuName: 'Premium' - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -207,9 +212,6 @@ module namespace 'br:bicep/modules/service-bus.namespace:1.0.0' = { ] } ] - userAssignedIdentities: { - '': {} - } zoneRedundant: true } } @@ -279,6 +281,14 @@ module namespace 'br:bicep/modules/service-bus.namespace:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "minimumTlsVersion": { "value": "1.2" }, @@ -374,9 +384,6 @@ module namespace 'br:bicep/modules/service-bus.namespace:1.0.0' = { "skuName": { "value": "Premium" }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", @@ -415,11 +422,6 @@ module namespace 'br:bicep/modules/service-bus.namespace:1.0.0' = { } ] }, - "userAssignedIdentities": { - "value": { - "": {} - } - }, "zoneRedundant": { "value": true } @@ -464,6 +466,12 @@ module namespace 'br:bicep/modules/service-bus.namespace:1.0.0' = { cMKKeyVaultResourceId: '' cMKUserAssignedIdentityResourceId: '' enableDefaultTelemetry: '' + managedIdentities: { + systemAssigned: false + userAssignedResourcesIds: [ + '' + ] + } networkRuleSets: { defaultAction: 'Deny' ipRules: [ @@ -492,15 +500,11 @@ module namespace 'br:bicep/modules/service-bus.namespace:1.0.0' = { } ] skuName: 'Premium' - systemAssignedIdentity: false tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -553,6 +557,14 @@ module namespace 'br:bicep/modules/service-bus.namespace:1.0.0' = { "enableDefaultTelemetry": { "value": "" }, + "managedIdentities": { + "value": { + "systemAssigned": false, + "userAssignedResourcesIds": [ + "" + ] + } + }, "networkRuleSets": { "value": { "defaultAction": "Deny", @@ -587,20 +599,12 @@ module namespace 'br:bicep/modules/service-bus.namespace:1.0.0' = { "skuName": { "value": "Premium" }, - "systemAssignedIdentity": { - "value": false - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -780,6 +784,7 @@ module namespace 'br:bicep/modules/service-bus.namespace:1.0.0' = { | [`enableDefaultTelemetry`](#parameter-enabledefaulttelemetry) | bool | Enable telemetry via a Globally Unique Identifier (GUID). | | [`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. | | [`migrationConfigurations`](#parameter-migrationconfigurations) | object | The migration configuration. | | [`minimumTlsVersion`](#parameter-minimumtlsversion) | string | The minimum TLS version for the cluster to support. | | [`networkRuleSets`](#parameter-networkrulesets) | object | Configure networking options for Premium SKU Service Bus. This object contains IPs/Subnets to allow or restrict access to private endpoints only. For security reasons, it is recommended to configure this object on the Namespace. | @@ -791,10 +796,8 @@ module namespace 'br:bicep/modules/service-bus.namespace:1.0.0' = { | [`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'. | | [`skuCapacity`](#parameter-skucapacity) | int | The specified messaging units for the tier. Only used for Premium Sku tier. | | [`skuName`](#parameter-skuname) | string | Name of this SKU. - Basic, Standard, Premium. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`topics`](#parameter-topics) | array | The topics to create in the service bus namespace. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`zoneRedundant`](#parameter-zoneredundant) | bool | Enabling this property creates a Premium Service Bus Namespace in regions supported availability zones. | ### Parameter: `alternateName` @@ -1009,6 +1012,32 @@ 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: `migrationConfigurations` The migration configuration. @@ -1318,13 +1347,6 @@ Name of this SKU. - Basic, Standard, Premium. - Default: `'Basic'` - Allowed: `[Basic, Premium, Standard]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -1339,13 +1361,6 @@ The topics to create in the service bus namespace. - Type: array - Default: `[]` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `zoneRedundant` Enabling this property creates a Premium Service Bus Namespace in regions supported availability zones. @@ -1362,7 +1377,7 @@ Enabling this property creates a Premium Service Bus Namespace in regions suppor | `name` | string | The name of the deployed service bus namespace. | | `resourceGroupName` | string | The resource group of the deployed service bus namespace. | | `resourceId` | string | The resource ID of the deployed service bus namespace. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/service-bus/namespace/main.bicep b/modules/service-bus/namespace/main.bicep index 87ecd77360..b78edd738f 100644 --- a/modules/service-bus/namespace/main.bicep +++ b/modules/service-bus/namespace/main.bicep @@ -69,11 +69,8 @@ param diagnosticSettings diagnosticSettingType @description('Optional. The lock settings of the service.') param lock lockType -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @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 @@ -123,11 +120,11 @@ param cMKUserAssignedIdentityResourceId string = '' @description('Optional. Enable infrastructure encryption (double encryption). Note, this setting requires the configuration of Customer-Managed-Keys (CMK) via the corresponding module parameters.') param requireInfrastructureEncryption bool = true -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 enableReferencedModulesTelemetry = false @@ -393,7 +390,7 @@ output resourceGroupName string = resourceGroup().name output name string = serviceBusNamespace.name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(serviceBusNamespace.identity, 'principalId') ? serviceBusNamespace.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(serviceBusNamespace.identity, 'principalId') ? serviceBusNamespace.identity.principalId : '' @description('The location the resource was deployed into.') output location string = serviceBusNamespace.location @@ -402,6 +399,14 @@ output location string = serviceBusNamespace.location // 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? diff --git a/modules/service-bus/namespace/main.json b/modules/service-bus/namespace/main.json index cc90af1105..5f9e473ae2 100644 --- a/modules/service-bus/namespace/main.json +++ b/modules/service-bus/namespace/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "5514287730537410098" + "templateHash": "14764861552700304868" }, "name": "Service Bus Namespaces", "description": "This module deploys a Service Bus Namespace.", "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": { @@ -477,18 +500,10 @@ "description": "Optional. The lock settings of the service." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "roleAssignments": { @@ -595,8 +610,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Azure Service Bus Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '090c5cfd-751d-490a-894a-3ce6f1109419')]", @@ -2972,12 +2987,12 @@ }, "value": "[parameters('name')]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('serviceBusNamespace', '2022-10-01-preview', 'full').identity, 'principalId')), reference('serviceBusNamespace', '2022-10-01-preview', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('serviceBusNamespace', '2022-10-01-preview', 'full').identity, 'principalId')), reference('serviceBusNamespace', '2022-10-01-preview', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/signal-r-service/web-pub-sub/.test/common/main.test.bicep b/modules/signal-r-service/web-pub-sub/.test/common/main.test.bicep index 93a4cde2c8..cc53d47085 100644 --- a/modules/signal-r-service/web-pub-sub/.test/common/main.test.bicep +++ b/modules/signal-r-service/web-pub-sub/.test/common/main.test.bicep @@ -107,7 +107,9 @@ module testDeployment '../../main.bicep' = { } ] sku: 'Standard_S1' - systemAssignedIdentity: true + managedIdentities: { + systemAssigned: true + } tags: { 'hidden-title': 'This is visible in the resource name' Environment: 'Non-Prod' diff --git a/modules/signal-r-service/web-pub-sub/README.md b/modules/signal-r-service/web-pub-sub/README.md index a1f443b2f3..802630e972 100644 --- a/modules/signal-r-service/web-pub-sub/README.md +++ b/modules/signal-r-service/web-pub-sub/README.md @@ -58,6 +58,9 @@ module webPubSub 'br:bicep/modules/signal-r-service.web-pub-sub:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + } networkAcls: { defaultAction: 'Allow' privateEndpoints: [ @@ -103,7 +106,6 @@ module webPubSub 'br:bicep/modules/signal-r-service.web-pub-sub:1.0.0' = { } ] sku: 'Standard_S1' - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -154,6 +156,11 @@ module webPubSub 'br:bicep/modules/signal-r-service.web-pub-sub:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, "networkAcls": { "value": { "defaultAction": "Allow", @@ -209,9 +216,6 @@ module webPubSub 'br:bicep/modules/signal-r-service.web-pub-sub:1.0.0' = { "sku": { "value": "Standard_S1" }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", @@ -383,15 +387,14 @@ module webPubSub 'br:bicep/modules/signal-r-service.web-pub-sub:1.0.0' = { | [`enableDefaultTelemetry`](#parameter-enabledefaulttelemetry) | bool | Enable telemetry via a Globally Unique Identifier (GUID). | | [`location`](#parameter-location) | string | The location for the resource. | | [`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. | | [`networkAcls`](#parameter-networkacls) | object | Networks ACLs, this value contains IPs to allow and/or Subnet information. Can only be set if the 'SKU' is not 'Free_F1'. For security reasons, it is recommended to set the DefaultAction Deny. | | [`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. | | [`resourceLogConfigurationsToEnable`](#parameter-resourcelogconfigurationstoenable) | array | Control permission for data plane traffic coming from public networks while private endpoint is enabled. | | [`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'. | | [`sku`](#parameter-sku) | string | Pricing tier of the resource. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | ### Parameter: `capacity` @@ -462,6 +465,32 @@ Optional. Specify the name of lock. - Required: No - Type: string +### Parameter: `managedIdentities` + +The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both. +- 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 Web PubSub Service resource. @@ -735,13 +764,6 @@ Pricing tier of the resource. - Default: `'Standard_S1'` - Allowed: `[Free_F1, Standard_S1]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -749,13 +771,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs @@ -769,6 +784,7 @@ The ID(s) to assign to the resource. | `resourceGroupName` | string | The Web PubSub resource group. | | `resourceId` | string | The Web PubSub resource ID. | | `serverPort` | int | The Web PubSub serverPort. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/signal-r-service/web-pub-sub/main.bicep b/modules/signal-r-service/web-pub-sub/main.bicep index 49fdc78208..70b93a62d7 100644 --- a/modules/signal-r-service/web-pub-sub/main.bicep +++ b/modules/signal-r-service/web-pub-sub/main.bicep @@ -30,11 +30,8 @@ param capacity int = 1 @description('Optional. Pricing tier of the resource.') param sku string = 'Standard_S1' -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both.') +param managedIdentities managedIdentitiesType @description('Optional. When set as true, connection with AuthType=aad won\'t work.') param disableAadAuth bool = false @@ -69,19 +66,19 @@ param networkAcls object = {} @description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') param enableDefaultTelemetry bool = true +var enableReferencedModulesTelemetry = false + var resourceLogConfiguration = [for configuration in resourceLogConfigurationsToEnable: { name: configuration enabled: 'true' }] -var identityType = systemAssignedIdentity ? 'SystemAssigned' : !empty(userAssignedIdentities) ? 'UserAssigned' : 'None' - -var enableReferencedModulesTelemetry = false +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 = { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null -} +var identity = !empty(managedIdentities) ? { + type: (managedIdentities.?systemAssigned ?? false) ? 'SystemAssigned' : (!empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null) + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null +} : null var builtInRoleNames = { Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') @@ -203,6 +200,9 @@ output publicPort int = webPubSub.properties.publicPort @description('The Web PubSub serverPort.') output serverPort int = webPubSub.properties.serverPort +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(webPubSub.identity, 'principalId') ? webPubSub.identity.principalId : '' + @description('The location the resource was deployed into.') output location string = webPubSub.location @@ -210,6 +210,14 @@ output location string = webPubSub.location // 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? diff --git a/modules/signal-r-service/web-pub-sub/main.json b/modules/signal-r-service/web-pub-sub/main.json index 224d8e6108..aa1f93b682 100644 --- a/modules/signal-r-service/web-pub-sub/main.json +++ b/modules/signal-r-service/web-pub-sub/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "17322937752748327397" + "templateHash": "12261287441324704754" }, "name": "SignalR Web PubSub Services", "description": "This module deploys a SignalR Web PubSub Service.", "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": { @@ -311,18 +334,10 @@ "description": "Optional. Pricing tier of the resource." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." } }, "disableAadAuth": { @@ -398,12 +413,9 @@ } } ], - "identityType": "[if(parameters('systemAssignedIdentity'), 'SystemAssigned', if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", "enableReferencedModulesTelemetry": false, - "identity": { - "type": "[variables('identityType')]", - "userAssignedIdentities": "[if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), 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(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), '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')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", @@ -1098,6 +1110,13 @@ }, "value": "[reference('webPubSub').serverPort]" }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('webPubSub', '2021-10-01', 'full').identity, 'principalId')), reference('webPubSub', '2021-10-01', 'full').identity.principalId, '')]" + }, "location": { "type": "string", "metadata": { diff --git a/modules/sql/managed-instance/.test/common/main.test.bicep b/modules/sql/managed-instance/.test/common/main.test.bicep index 64c6288ad0..d5222b8617 100644 --- a/modules/sql/managed-instance/.test/common/main.test.bicep +++ b/modules/sql/managed-instance/.test/common/main.test.bicep @@ -154,11 +154,13 @@ module testDeployment '../../main.bicep' = { skuName: 'GP_Gen5' skuTier: 'GeneralPurpose' storageSizeInGB: 32 - systemAssignedIdentity: true - timezoneId: 'UTC' - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } + timezoneId: 'UTC' vCores: 4 vulnerabilityAssessmentsObj: { emailSubscriptionAdmins: true diff --git a/modules/sql/managed-instance/.test/vulnAssm/main.test.bicep b/modules/sql/managed-instance/.test/vulnAssm/main.test.bicep index aecb08b1b7..bbe2806291 100644 --- a/modules/sql/managed-instance/.test/vulnAssm/main.test.bicep +++ b/modules/sql/managed-instance/.test/vulnAssm/main.test.bicep @@ -60,7 +60,9 @@ module testDeployment '../../main.bicep' = { administratorLogin: 'adminUserName' administratorLoginPassword: password subnetId: nestedDependencies.outputs.subnetResourceId - systemAssignedIdentity: true + managedIdentities: { + systemAssigned: true + } securityAlertPoliciesObj: { emailAccountAdmins: true name: 'default' diff --git a/modules/sql/managed-instance/README.md b/modules/sql/managed-instance/README.md index 0c6387413b..aa416f045a 100644 --- a/modules/sql/managed-instance/README.md +++ b/modules/sql/managed-instance/README.md @@ -113,6 +113,12 @@ module managedInstance 'br:bicep/modules/sql.managed-instance:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } primaryUserAssignedIdentityId: '' proxyOverride: 'Proxy' publicDataEndpointEnabled: false @@ -132,11 +138,7 @@ module managedInstance 'br:bicep/modules/sql.managed-instance:1.0.0' = { skuName: 'GP_Gen5' skuTier: 'GeneralPurpose' storageSizeInGB: 32 - systemAssignedIdentity: true timezoneId: 'UTC' - userAssignedIdentities: { - '': {} - } vCores: 4 vulnerabilityAssessmentsObj: { emailSubscriptionAdmins: true @@ -255,6 +257,14 @@ module managedInstance 'br:bicep/modules/sql.managed-instance:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "primaryUserAssignedIdentityId": { "value": "" }, @@ -292,17 +302,9 @@ module managedInstance 'br:bicep/modules/sql.managed-instance:1.0.0' = { "storageSizeInGB": { "value": 32 }, - "systemAssignedIdentity": { - "value": true - }, "timezoneId": { "value": "UTC" }, - "userAssignedIdentities": { - "value": { - "": {} - } - }, "vCores": { "value": 4 }, @@ -407,12 +409,14 @@ module managedInstance 'br:bicep/modules/sql.managed-instance:1.0.0' = { subnetId: '' // Non-required parameters enableDefaultTelemetry: '' + managedIdentities: { + systemAssigned: true + } securityAlertPoliciesObj: { emailAccountAdmins: true name: 'default' state: 'Enabled' } - systemAssignedIdentity: true vulnerabilityAssessmentsObj: { createStorageRoleAssignment: true emailSubscriptionAdmins: true @@ -463,6 +467,11 @@ module managedInstance 'br:bicep/modules/sql.managed-instance:1.0.0' = { "enableDefaultTelemetry": { "value": "" }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, "securityAlertPoliciesObj": { "value": { "emailAccountAdmins": true, @@ -470,9 +479,6 @@ module managedInstance 'br:bicep/modules/sql.managed-instance:1.0.0' = { "state": "Enabled" } }, - "systemAssignedIdentity": { - "value": true - }, "vulnerabilityAssessmentsObj": { "value": { "createStorageRoleAssignment": true, @@ -534,6 +540,7 @@ module managedInstance 'br:bicep/modules/sql.managed-instance:1.0.0' = { | [`licenseType`](#parameter-licensetype) | string | The license type. Possible values are 'LicenseIncluded' (regular price inclusive of a new SQL license) and 'BasePrice' (discounted AHB price for bringing your own SQL licenses). | | [`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. | | [`managedInstanceCreateMode`](#parameter-managedinstancecreatemode) | string | Specifies the mode of database creation. Default: Regular instance creation. Restore: Creates an instance by restoring a set of backups to specific point in time. RestorePointInTime and SourceManagedInstanceId must be specified. | | [`minimalTlsVersion`](#parameter-minimaltlsversion) | string | Minimal TLS version allowed. | | [`proxyOverride`](#parameter-proxyoverride) | string | Connection type used for connecting to the instance. | @@ -547,10 +554,8 @@ module managedInstance 'br:bicep/modules/sql.managed-instance:1.0.0' = { | [`skuTier`](#parameter-skutier) | string | The tier or edition of the particular SKU, e.g. Basic, Premium. | | [`sourceManagedInstanceId`](#parameter-sourcemanagedinstanceid) | string | The resource identifier of the source managed instance associated with create operation of this instance. | | [`storageSizeInGB`](#parameter-storagesizeingb) | int | Storage size in GB. Minimum value: 32. Maximum value: 8192. Increments of 32 GB allowed only. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`timezoneId`](#parameter-timezoneid) | string | ID of the timezone. Allowed values are timezones supported by Windows. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`vCores`](#parameter-vcores) | int | The number of vCores. Allowed values: 8, 16, 24, 32, 40, 64, 80. | | [`vulnerabilityAssessmentsObj`](#parameter-vulnerabilityassessmentsobj) | object | The vulnerability assessment configuration. | | [`zoneRedundant`](#parameter-zoneredundant) | bool | Whether or not multi-az is enabled. | @@ -787,6 +792,32 @@ 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: `managedInstanceCreateMode` Specifies the mode of database creation. Default: Regular instance creation. Restore: Creates an instance by restoring a set of backups to specific point in time. RestorePointInTime and SourceManagedInstanceId must be specified. @@ -963,13 +994,6 @@ The fully qualified resource ID of the subnet on which the SQL managed instance - Required: Yes - Type: string -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -984,13 +1008,6 @@ ID of the timezone. Allowed values are timezones supported by Windows. - Type: string - Default: `'UTC'` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `vCores` The number of vCores. Allowed values: 8, 16, 24, 32, 40, 64, 80. @@ -1021,7 +1038,7 @@ Whether or not multi-az is enabled. | `name` | string | The name of the deployed managed instance. | | `resourceGroupName` | string | The resource group of the deployed managed instance. | | `resourceId` | string | The resource ID of the deployed managed instance. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/sql/managed-instance/main.bicep b/modules/sql/managed-instance/main.bicep index 330edebd43..1b10ecd747 100644 --- a/modules/sql/managed-instance/main.bicep +++ b/modules/sql/managed-instance/main.bicep @@ -101,11 +101,8 @@ param tags object = {} @description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') param enableDefaultTelemetry bool = true -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Conditional. The resource ID of a user assigned identity to be used by default. Required if "userAssignedIdentities" is not empty.') param primaryUserAssignedIdentityId string = '' @@ -146,11 +143,11 @@ param minimalTlsVersion string = '1.2' ]) param requestedBackupStorageRedundancy string = 'Geo' -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 enableReferencedModulesTelemetry = false @@ -303,7 +300,7 @@ module managedInstance_securityAlertPolicy 'security-alert-policy/main.bicep' = } } -module managedInstance_vulnerabilityAssessment 'vulnerability-assessment/main.bicep' = if (!empty(vulnerabilityAssessmentsObj) && systemAssignedIdentity) { +module managedInstance_vulnerabilityAssessment 'vulnerability-assessment/main.bicep' = if (!empty(vulnerabilityAssessmentsObj) && (managedIdentities.?systemAssigned ?? false)) { name: '${uniqueString(deployment().name, location)}-SqlMi-VulnAssessm' params: { managedInstanceName: managedInstance.name @@ -367,7 +364,7 @@ output resourceId string = managedInstance.id output resourceGroupName string = resourceGroup().name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(managedInstance.identity, 'principalId') ? managedInstance.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(managedInstance.identity, 'principalId') ? managedInstance.identity.principalId : '' @description('The location the resource was deployed into.') output location string = managedInstance.location @@ -376,6 +373,14 @@ output location string = managedInstance.location // 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? diff --git a/modules/sql/managed-instance/main.json b/modules/sql/managed-instance/main.json index 646e61a20a..cee9076a62 100644 --- a/modules/sql/managed-instance/main.json +++ b/modules/sql/managed-instance/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "16983144264523357035" + "templateHash": "486965125676503752" }, "name": "SQL Managed Instances", "description": "This module deploys a SQL Managed Instance.", "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": { @@ -411,18 +434,10 @@ "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "primaryUserAssignedIdentityId": { @@ -502,8 +517,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", @@ -1468,7 +1483,7 @@ ] }, "managedInstance_vulnerabilityAssessment": { - "condition": "[and(not(empty(parameters('vulnerabilityAssessmentsObj'))), parameters('systemAssignedIdentity'))]", + "condition": "[and(not(empty(parameters('vulnerabilityAssessmentsObj'))), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[format('{0}-SqlMi-VulnAssessm', uniqueString(deployment().name, parameters('location')))]", @@ -2102,12 +2117,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('managedInstance', '2022-05-01-preview', 'full').identity, 'principalId')), reference('managedInstance', '2022-05-01-preview', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('managedInstance', '2022-05-01-preview', 'full').identity, 'principalId')), reference('managedInstance', '2022-05-01-preview', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/sql/server/.test/common/main.test.bicep b/modules/sql/server/.test/common/main.test.bicep index 0655a40b92..e5a989eec6 100644 --- a/modules/sql/server/.test/common/main.test.bicep +++ b/modules/sql/server/.test/common/main.test.bicep @@ -160,9 +160,11 @@ module testDeployment '../../main.bicep' = { uri: nestedDependencies.outputs.keyVaultEncryptionKeyUrl } ] - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } privateEndpoints: [ { diff --git a/modules/sql/server/.test/vulnAssm/main.test.bicep b/modules/sql/server/.test/vulnAssm/main.test.bicep index 5dd0f342e9..4ee3ba8505 100644 --- a/modules/sql/server/.test/vulnAssm/main.test.bicep +++ b/modules/sql/server/.test/vulnAssm/main.test.bicep @@ -78,9 +78,11 @@ module testDeployment '../../main.bicep' = { emailAccountAdmins: true } ] - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/modules/sql/server/README.md b/modules/sql/server/README.md index 5acbefa33c..81fa6667cc 100644 --- a/modules/sql/server/README.md +++ b/modules/sql/server/README.md @@ -185,6 +185,12 @@ module server 'br:bicep/modules/sql.server:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } primaryUserAssignedIdentityId: '' privateEndpoints: [ { @@ -215,15 +221,11 @@ module server 'br:bicep/modules/sql.server:1.0.0' = { state: 'Enabled' } ] - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } virtualNetworkRules: [ { ignoreMissingVnetServiceEndpoint: true @@ -340,6 +342,14 @@ module server 'br:bicep/modules/sql.server:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "primaryUserAssignedIdentityId": { "value": "" }, @@ -380,9 +390,6 @@ module server 'br:bicep/modules/sql.server:1.0.0' = { } ] }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", @@ -390,11 +397,6 @@ module server 'br:bicep/modules/sql.server:1.0.0' = { "Role": "DeploymentValidation" } }, - "userAssignedIdentities": { - "value": { - "": {} - } - }, "virtualNetworkRules": { "value": [ { @@ -620,6 +622,12 @@ module server 'br:bicep/modules/sql.server:1.0.0' = { administratorLoginPassword: '' enableDefaultTelemetry: '' location: '' + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } primaryUserAssignedIdentityId: '' securityAlertPolicies: [ { @@ -628,15 +636,11 @@ module server 'br:bicep/modules/sql.server:1.0.0' = { state: 'Enabled' } ] - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } vulnerabilityAssessmentsObj: { createStorageRoleAssignment: true emailSubscriptionAdmins: true @@ -682,6 +686,14 @@ module server 'br:bicep/modules/sql.server:1.0.0' = { "location": { "value": "" }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "primaryUserAssignedIdentityId": { "value": "" }, @@ -694,9 +706,6 @@ module server 'br:bicep/modules/sql.server:1.0.0' = { } ] }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", @@ -704,11 +713,6 @@ module server 'br:bicep/modules/sql.server:1.0.0' = { "Role": "DeploymentValidation" } }, - "userAssignedIdentities": { - "value": { - "": {} - } - }, "vulnerabilityAssessmentsObj": { "value": { "createStorageRoleAssignment": true, @@ -760,15 +764,14 @@ module server 'br:bicep/modules/sql.server:1.0.0' = { | [`keys`](#parameter-keys) | array | The keys to configure. | | [`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. | | [`minimalTlsVersion`](#parameter-minimaltlsversion) | string | Minimal TLS version allowed. | | [`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'. | | [`securityAlertPolicies`](#parameter-securityalertpolicies) | array | The security alert policies to create in the server. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`virtualNetworkRules`](#parameter-virtualnetworkrules) | array | The virtual network rules to create in the server. | | [`vulnerabilityAssessmentsObj`](#parameter-vulnerabilityassessmentsobj) | object | The vulnerability assessment configuration. | @@ -869,6 +872,32 @@ 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: `minimalTlsVersion` Minimal TLS version allowed. @@ -1149,13 +1178,6 @@ The security alert policies to create in the server. - Type: array - Default: `[]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -1163,13 +1185,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `virtualNetworkRules` The virtual network rules to create in the server. @@ -1193,7 +1208,7 @@ The vulnerability assessment configuration. | `name` | string | The name of the deployed SQL server. | | `resourceGroupName` | string | The resource group of the deployed SQL server. | | `resourceId` | string | The resource ID of the deployed SQL server. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/sql/server/main.bicep b/modules/sql/server/main.bicep index fa4351217e..50bfad6e00 100644 --- a/modules/sql/server/main.bicep +++ b/modules/sql/server/main.bicep @@ -15,11 +15,8 @@ param location string = resourceGroup().location @description('Required. The name of the server.') param name string -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Conditional. The resource ID of a user assigned identity to be used by default. Required if "userAssignedIdentities" is not empty.') param primaryUserAssignedIdentityId string = '' @@ -84,11 +81,11 @@ param publicNetworkAccess string = '' ]) param restrictOutboundNetworkAccess string = '' -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 enableReferencedModulesTelemetry = false @@ -350,7 +347,7 @@ output resourceId string = server.id output resourceGroupName string = resourceGroup().name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(server.identity, 'principalId') ? server.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(server.identity, 'principalId') ? server.identity.principalId : '' @description('The location the resource was deployed into.') output location string = server.location @@ -359,6 +356,14 @@ output location string = server.location // 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? diff --git a/modules/sql/server/main.json b/modules/sql/server/main.json index 15f464c1bd..44de76b732 100644 --- a/modules/sql/server/main.json +++ b/modules/sql/server/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "9008744149978786783" + "templateHash": "10315505573708385972" }, "name": "Azure SQL Servers", "description": "This module deploys an Azure SQL Server.", "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": { @@ -282,18 +305,10 @@ "description": "Required. The name of the server." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "primaryUserAssignedIdentityId": { @@ -436,8 +451,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", @@ -3062,12 +3077,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('server', '2022-05-01-preview', 'full').identity, 'principalId')), reference('server', '2022-05-01-preview', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('server', '2022-05-01-preview', 'full').identity, 'principalId')), reference('server', '2022-05-01-preview', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/storage/storage-account/.test/common/main.test.bicep b/modules/storage/storage-account/.test/common/main.test.bicep index 752c544377..2ca85cdb7f 100644 --- a/modules/storage/storage-account/.test/common/main.test.bicep +++ b/modules/storage/storage-account/.test/common/main.test.bicep @@ -263,9 +263,11 @@ module testDeployment '../../main.bicep' = { ] } sasExpirationPeriod: '180.00:00:00' - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } roleAssignments: [ { diff --git a/modules/storage/storage-account/.test/encr/main.test.bicep b/modules/storage/storage-account/.test/encr/main.test.bicep index acdcccd5d9..8a298cdee5 100644 --- a/modules/storage/storage-account/.test/encr/main.test.bicep +++ b/modules/storage/storage-account/.test/encr/main.test.bicep @@ -93,9 +93,11 @@ module testDeployment '../../main.bicep' = { restorePolicyEnabled: true restorePolicyDays: 8 } - systemAssignedIdentity: false - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: false + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } cMKKeyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId cMKKeyName: nestedDependencies.outputs.keyName diff --git a/modules/storage/storage-account/.test/nfs/main.test.bicep b/modules/storage/storage-account/.test/nfs/main.test.bicep index 180b8abb81..8dbf40c70a 100644 --- a/modules/storage/storage-account/.test/nfs/main.test.bicep +++ b/modules/storage/storage-account/.test/nfs/main.test.bicep @@ -79,9 +79,11 @@ module testDeployment '../../main.bicep' = { } ] } - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } roleAssignments: [ { diff --git a/modules/storage/storage-account/README.md b/modules/storage/storage-account/README.md index 956cc7475f..e974443c9d 100644 --- a/modules/storage/storage-account/README.md +++ b/modules/storage/storage-account/README.md @@ -185,6 +185,12 @@ module storageAccount 'br:bicep/modules/storage.storage-account:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } managementPolicyRules: [ { definition: { @@ -295,7 +301,6 @@ module storageAccount 'br:bicep/modules/storage.storage-account:1.0.0' = { ] sasExpirationPeriod: '180.00:00:00' skuName: 'Standard_LRS' - systemAssignedIdentity: true tableServices: { diagnosticSettings: [ { @@ -321,9 +326,6 @@ module storageAccount 'br:bicep/modules/storage.storage-account:1.0.0' = { 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -489,6 +491,14 @@ module storageAccount 'br:bicep/modules/storage.storage-account:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "managementPolicyRules": { "value": [ { @@ -615,9 +625,6 @@ module storageAccount 'br:bicep/modules/storage.storage-account:1.0.0' = { "skuName": { "value": "Standard_LRS" }, - "systemAssignedIdentity": { - "value": true - }, "tableServices": { "value": { "diagnosticSettings": [ @@ -646,11 +653,6 @@ module storageAccount 'br:bicep/modules/storage.storage-account:1.0.0' = { "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -698,6 +700,12 @@ module storageAccount 'br:bicep/modules/storage.storage-account:1.0.0' = { cMKKeyVaultResourceId: '' cMKUserAssignedIdentityResourceId: '' enableDefaultTelemetry: '' + managedIdentities: { + systemAssigned: false + userAssignedResourcesIds: [ + '' + ] + } privateEndpoints: [ { privateDnsZoneResourceIds: [ @@ -714,15 +722,11 @@ module storageAccount 'br:bicep/modules/storage.storage-account:1.0.0' = { ] requireInfrastructureEncryption: true skuName: 'Standard_LRS' - systemAssignedIdentity: false tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -782,6 +786,14 @@ module storageAccount 'br:bicep/modules/storage.storage-account:1.0.0' = { "enableDefaultTelemetry": { "value": "" }, + "managedIdentities": { + "value": { + "systemAssigned": false, + "userAssignedResourcesIds": [ + "" + ] + } + }, "privateEndpoints": { "value": [ { @@ -804,20 +816,12 @@ module storageAccount 'br:bicep/modules/storage.storage-account:1.0.0' = { "skuName": { "value": "Standard_LRS" }, - "systemAssignedIdentity": { - "value": false - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -920,6 +924,12 @@ module storageAccount 'br:bicep/modules/storage.storage-account:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } roleAssignments: [ { principalId: '' @@ -929,15 +939,11 @@ module storageAccount 'br:bicep/modules/storage.storage-account:1.0.0' = { ] skuName: 'Premium_LRS' supportsHttpsTrafficOnly: false - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -1000,6 +1006,14 @@ module storageAccount 'br:bicep/modules/storage.storage-account:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "roleAssignments": { "value": [ { @@ -1015,20 +1029,12 @@ module storageAccount 'br:bicep/modules/storage.storage-account:1.0.0' = { "supportsHttpsTrafficOnly": { "value": false }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -1147,6 +1153,7 @@ module storageAccount 'br:bicep/modules/storage.storage-account:1.0.0' = { | [`localUsers`](#parameter-localusers) | array | Local users to deploy for SFTP authentication. | | [`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. | | [`managementPolicyRules`](#parameter-managementpolicyrules) | array | The Storage Account ManagementPolicies Rules. | | [`minimumTlsVersion`](#parameter-minimumtlsversion) | string | Set the minimum TLS version on request to storage. | | [`networkAcls`](#parameter-networkacls) | object | Networks ACLs, this value contains IPs to whitelist and/or Subnet information. For security reasons, it is recommended to set the DefaultAction Deny. | @@ -1158,10 +1165,8 @@ module storageAccount 'br:bicep/modules/storage.storage-account:1.0.0' = { | [`sasExpirationPeriod`](#parameter-sasexpirationperiod) | string | The SAS expiration period. DD.HH:MM:SS. | | [`skuName`](#parameter-skuname) | string | Storage Account Sku Name. | | [`supportsHttpsTrafficOnly`](#parameter-supportshttpstrafficonly) | bool | Allows HTTPS traffic only to storage service if sets to true. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tableServices`](#parameter-tableservices) | object | Table service and tables to create. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | ### Parameter: `accessTier` @@ -1457,6 +1462,32 @@ 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: `managementPolicyRules` The Storage Account ManagementPolicies Rules. @@ -1765,13 +1796,6 @@ Allows HTTPS traffic only to storage service if sets to true. - Type: bool - Default: `True` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tableServices` Table service and tables to create. @@ -1786,13 +1810,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs @@ -1803,7 +1820,7 @@ The ID(s) to assign to the resource. | `primaryBlobEndpoint` | string | The primary blob endpoint reference if blob services are deployed. | | `resourceGroupName` | string | The resource group of the deployed storage account. | | `resourceId` | string | The resource ID of the deployed storage account. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/storage/storage-account/main.bicep b/modules/storage/storage-account/main.bicep index e8774101f0..42f8b18c1f 100644 --- a/modules/storage/storage-account/main.bicep +++ b/modules/storage/storage-account/main.bicep @@ -12,11 +12,8 @@ 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\'.') param roleAssignments roleAssignmentType -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @allowed([ 'Storage' @@ -181,10 +178,11 @@ param sasExpirationPeriod string = '' var supportsBlobService = kind == 'BlockBlobStorage' || kind == 'BlobStorage' || kind == 'StorageV2' || kind == 'Storage' var supportsFileService = kind == 'FileStorage' || kind == 'StorageV2' || kind == 'Storage' -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') -var identity = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : 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: (managedIdentities.?systemAssigned ?? false) ? (!empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null) + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } : null var enableReferencedModulesTelemetry = false @@ -473,7 +471,7 @@ output resourceGroupName string = resourceGroup().name output primaryBlobEndpoint string = !empty(blobServices) && contains(blobServices, 'containers') ? reference('Microsoft.Storage/storageAccounts/${storageAccount.name}', '2019-04-01').primaryEndpoints.blob : '' @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(storageAccount.identity, 'principalId') ? storageAccount.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(storageAccount.identity, 'principalId') ? storageAccount.identity.principalId : '' @description('The location the resource was deployed into.') output location string = storageAccount.location @@ -482,6 +480,14 @@ output location string = storageAccount.location // 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? diff --git a/modules/storage/storage-account/main.json b/modules/storage/storage-account/main.json index a476db610d..dde38f6c5b 100644 --- a/modules/storage/storage-account/main.json +++ b/modules/storage/storage-account/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "15002662159872818227" + "templateHash": "1854017442729323429" }, "name": "Storage Accounts", "description": "This module deploys a Storage Account.", "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": { @@ -354,18 +377,10 @@ "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'." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "kind": { @@ -681,8 +696,8 @@ "variables": { "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", @@ -4092,12 +4107,12 @@ }, "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('storageAccount', '2022-09-01', 'full').identity, 'principalId')), reference('storageAccount', '2022-09-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('storageAccount', '2022-09-01', 'full').identity, 'principalId')), reference('storageAccount', '2022-09-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/web/hosting-environment/.test/asev2/main.test.bicep b/modules/web/hosting-environment/.test/asev2/main.test.bicep index ff34db8bf0..835d050137 100644 --- a/modules/web/hosting-environment/.test/asev2/main.test.bicep +++ b/modules/web/hosting-environment/.test/asev2/main.test.bicep @@ -98,9 +98,11 @@ module testDeployment '../../main.bicep' = { workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId } ] - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } ipsslAddressCount: 2 kind: 'ASEv2' diff --git a/modules/web/hosting-environment/.test/asev3/main.test.bicep b/modules/web/hosting-environment/.test/asev3/main.test.bicep index 8349a9a8b0..d7045c104e 100644 --- a/modules/web/hosting-environment/.test/asev3/main.test.bicep +++ b/modules/web/hosting-environment/.test/asev3/main.test.bicep @@ -106,9 +106,11 @@ module testDeployment '../../main.bicep' = { workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId } ] - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } customDnsSuffix: 'internal.contoso.com' customDnsSuffixCertificateUrl: nestedDependencies.outputs.certificateSecretUrl diff --git a/modules/web/hosting-environment/README.md b/modules/web/hosting-environment/README.md index 8e8690e35a..e41afff80c 100644 --- a/modules/web/hosting-environment/README.md +++ b/modules/web/hosting-environment/README.md @@ -68,6 +68,12 @@ module hostingEnvironment 'br:bicep/modules/web.hosting-environment:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } multiSize: 'Standard_D1_V2' roleAssignments: [ { @@ -76,15 +82,11 @@ module hostingEnvironment 'br:bicep/modules/web.hosting-environment:1.0.0' = { roleDefinitionIdOrName: 'Reader' } ] - systemAssignedIdentity: true tags: { 'hidden-title': 'This is visible in the resource name' hostingEnvironmentName: 'whasev2001' resourceType: 'App Service Environment' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -146,6 +148,14 @@ module hostingEnvironment 'br:bicep/modules/web.hosting-environment:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "multiSize": { "value": "Standard_D1_V2" }, @@ -158,20 +168,12 @@ module hostingEnvironment 'br:bicep/modules/web.hosting-environment:1.0.0' = { } ] }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "hidden-title": "This is visible in the resource name", "hostingEnvironmentName": "whasev2001", "resourceType": "App Service Environment" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -222,6 +224,12 @@ module hostingEnvironment 'br:bicep/modules/web.hosting-environment:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } remoteDebugEnabled: true roleAssignments: [ { @@ -230,16 +238,12 @@ module hostingEnvironment 'br:bicep/modules/web.hosting-environment:1.0.0' = { roleDefinitionIdOrName: 'Reader' } ] - systemAssignedIdentity: true tags: { 'hidden-title': 'This is visible in the resource name' hostingEnvironmentName: 'whasev3001' resourceType: 'App Service Environment' } upgradePreference: 'Late' - userAssignedIdentities: { - '': {} - } } } ``` @@ -316,6 +320,14 @@ module hostingEnvironment 'br:bicep/modules/web.hosting-environment:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "remoteDebugEnabled": { "value": true }, @@ -328,9 +340,6 @@ module hostingEnvironment 'br:bicep/modules/web.hosting-environment:1.0.0' = { } ] }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "hidden-title": "This is visible in the resource name", @@ -340,11 +349,6 @@ module hostingEnvironment 'br:bicep/modules/web.hosting-environment:1.0.0' = { }, "upgradePreference": { "value": "Late" - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -389,13 +393,12 @@ module hostingEnvironment 'br:bicep/modules/web.hosting-environment:1.0.0' = { | [`kind`](#parameter-kind) | string | Kind of resource. | | [`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. | | [`multiSize`](#parameter-multisize) | string | Frontend VM size. Cannot be used when kind is set to ASEv3. | | [`remoteDebugEnabled`](#parameter-remotedebugenabled) | bool | Property to enable and disable Remote Debug on ASEv3. Ignored when kind is set to ASEv2. | | [`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'. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Resource tags. | | [`upgradePreference`](#parameter-upgradepreference) | string | Specify preference for when and how the planned maintenance is applied. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`userWhitelistedIpRanges`](#parameter-userwhitelistedipranges) | array | User added IP ranges to whitelist on ASE DB. Cannot be used with 'kind' `ASEv3`. | | [`zoneRedundant`](#parameter-zoneredundant) | bool | Switch to make the App Service Environment zone redundant. If enabled, the minimum App Service plan instance count will be three, otherwise 1. If enabled, the `dedicatedHostCount` must be set to `-1`. | @@ -628,6 +631,32 @@ 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: `multiSize` Frontend VM size. Cannot be used when kind is set to ASEv3. @@ -723,13 +752,6 @@ ResourceId for the subnet. - Required: Yes - Type: string -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Resource tags. @@ -745,13 +767,6 @@ Specify preference for when and how the planned maintenance is applied. - Default: `'None'` - Allowed: `[Early, Late, Manual, None]` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `userWhitelistedIpRanges` User added IP ranges to whitelist on ASE DB. Cannot be used with 'kind' `ASEv3`. diff --git a/modules/web/hosting-environment/main.bicep b/modules/web/hosting-environment/main.bicep index da6d56d178..f39bc28623 100644 --- a/modules/web/hosting-environment/main.bicep +++ b/modules/web/hosting-environment/main.bicep @@ -109,11 +109,8 @@ param userWhitelistedIpRanges array = [] @description('Optional. Switch to make the App Service Environment zone redundant. If enabled, the minimum App Service plan instance count will be three, otherwise 1. If enabled, the `dedicatedHostCount` must be set to `-1`.') param zoneRedundant bool = false -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. The diagnostic settings of the service.') param diagnosticSettings diagnosticSettingType @@ -121,14 +118,15 @@ param diagnosticSettings diagnosticSettingType @description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') param enableDefaultTelemetry bool = true -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') -var enableReferencedModulesTelemetry = false +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +var identity = !empty(managedIdentities) ? { + type: (managedIdentities.?systemAssigned ?? false) ? (!empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(managedIdentities.?userAssignedResourcesIds ?? {}) ? 'UserAssigned' : null) + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } : any(null) +var enableReferencedModulesTelemetry = false + var builtInRoleNames = { Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') @@ -254,6 +252,14 @@ output location string = appServiceEnvironment.location // 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? diff --git a/modules/web/hosting-environment/main.json b/modules/web/hosting-environment/main.json index cd15bf4aab..468a1dd392 100644 --- a/modules/web/hosting-environment/main.json +++ b/modules/web/hosting-environment/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "11474223450734881423" + "templateHash": "4072056725724568319" }, "name": "App Service Environments", "description": "This module deploys an App Service Environment.", "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": { @@ -393,18 +416,10 @@ "description": "Optional. Switch to make the App Service Environment zone redundant. If enabled, the minimum App Service plan instance count will be three, otherwise 1. If enabled, the `dedicatedHostCount` must be set to `-1`." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "diagnosticSettings": { @@ -422,9 +437,9 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", + "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())]", "enableReferencedModulesTelemetry": false, - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), null())]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", diff --git a/modules/web/site/.test/functionAppCommon/main.test.bicep b/modules/web/site/.test/functionAppCommon/main.test.bicep index 2a2af35a66..afc7ec0eec 100644 --- a/modules/web/site/.test/functionAppCommon/main.test.bicep +++ b/modules/web/site/.test/functionAppCommon/main.test.bicep @@ -185,9 +185,11 @@ module testDeployment '../../main.bicep' = { use32BitWorkerProcess: false } storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } hybridConnectionRelays: [ { diff --git a/modules/web/site/.test/webAppCommon/main.test.bicep b/modules/web/site/.test/webAppCommon/main.test.bicep index 6e61619316..e0b0545fc6 100644 --- a/modules/web/site/.test/webAppCommon/main.test.bicep +++ b/modules/web/site/.test/webAppCommon/main.test.bicep @@ -170,9 +170,11 @@ module testDeployment '../../main.bicep' = { } ] } - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } basicPublishingCredentialsPolicies: [ { diff --git a/modules/web/site/README.md b/modules/web/site/README.md index 72c2066fe8..160432f44c 100644 --- a/modules/web/site/README.md +++ b/modules/web/site/README.md @@ -151,6 +151,12 @@ module site 'br:bicep/modules/web.site:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } privateEndpoints: [ { privateDnsZoneResourceIds: [ @@ -177,10 +183,6 @@ module site 'br:bicep/modules/web.site:1.0.0' = { use32BitWorkerProcess: false } storageAccountResourceId: '' - systemAssignedIdentity: true - userAssignedIdentities: { - '': {} - } } } ``` @@ -319,6 +321,14 @@ module site 'br:bicep/modules/web.site:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "privateEndpoints": { "value": [ { @@ -354,14 +364,6 @@ module site 'br:bicep/modules/web.site:1.0.0' = { }, "storageAccountResourceId": { "value": "" - }, - "systemAssignedIdentity": { - "value": true - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -480,6 +482,12 @@ module site 'br:bicep/modules/web.site:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } privateEndpoints: [ { privateDnsZoneResourceIds: [ @@ -563,10 +571,6 @@ module site 'br:bicep/modules/web.site:1.0.0' = { name: 'slot2' } ] - systemAssignedIdentity: true - userAssignedIdentities: { - '': {} - } vnetContentShareEnabled: true vnetImagePullEnabled: true vnetRouteAllEnabled: true @@ -643,6 +647,14 @@ module site 'br:bicep/modules/web.site:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "privateEndpoints": { "value": [ { @@ -738,14 +750,6 @@ module site 'br:bicep/modules/web.site:1.0.0' = { } ] }, - "systemAssignedIdentity": { - "value": true - }, - "userAssignedIdentities": { - "value": { - "": {} - } - }, "vnetContentShareEnabled": { "value": true }, @@ -853,6 +857,7 @@ module site 'br:bicep/modules/web.site:1.0.0' = { | [`keyVaultAccessIdentityResourceId`](#parameter-keyvaultaccessidentityresourceid) | string | The resource ID of the assigned identity to be used to access a key vault with. | | [`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. | | [`redundancyMode`](#parameter-redundancymode) | string | Site redundancy mode. | @@ -863,9 +868,7 @@ module site 'br:bicep/modules/web.site:1.0.0' = { | [`slots`](#parameter-slots) | array | Configuration for deployment slots for an app. | | [`storageAccountRequired`](#parameter-storageaccountrequired) | bool | Checks if Customer provided storage account is required. | | [`storageAccountResourceId`](#parameter-storageaccountresourceid) | string | Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`virtualNetworkSubnetId`](#parameter-virtualnetworksubnetid) | string | Azure Resource Manager ID of the Virtual network and subnet to be joined by Regional VNET Integration. This must be of the form /subscriptions/{subscriptionName}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{vnetName}/subnets/{subnetName}. | | [`vnetContentShareEnabled`](#parameter-vnetcontentshareenabled) | bool | To enable accessing content over virtual network. | | [`vnetImagePullEnabled`](#parameter-vnetimagepullenabled) | bool | To enable pulling image over Virtual Network. | @@ -1168,6 +1171,32 @@ 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` Name of the site. @@ -1474,13 +1503,6 @@ Required if app of kind functionapp. Resource ID of the storage account to manag - Type: string - Default: `''` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -1488,13 +1510,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `virtualNetworkSubnetId` Azure Resource Manager ID of the Virtual network and subnet to be joined by Regional VNET Integration. This must be of the form /subscriptions/{subscriptionName}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{vnetName}/subnets/{subnetName}. @@ -1536,7 +1551,7 @@ Virtual Network Route All enabled. This causes all outbound traffic to have Virt | `slotResourceIds` | array | The list of the slot resource ids. | | `slots` | array | The list of the slots. | | `slotSystemAssignedPrincipalIds` | array | The principal ID of the system assigned identity of slots. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/web/site/main.bicep b/modules/web/site/main.bicep index 6e5951ac44..4add5b8016 100644 --- a/modules/web/site/main.bicep +++ b/modules/web/site/main.bicep @@ -30,11 +30,8 @@ param clientAffinityEnabled bool = true @description('Optional. The resource ID of the app service environment to use for this resource.') param appServiceEnvironmentResourceId string = '' -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. The resource ID of the assigned identity to be used to access a key vault with.') param keyVaultAccessIdentityResourceId string = '' @@ -155,11 +152,11 @@ param hybridConnectionRelays array = [] ]) param publicNetworkAccess string = '' -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 enableReferencedModulesTelemetry = false @@ -258,8 +255,7 @@ module app_slots 'slot/main.bicep' = [for (slot, index) in slots: { httpsOnly: contains(slot, 'httpsOnly') ? slot.httpsOnly : httpsOnly appServiceEnvironmentResourceId: !empty(appServiceEnvironmentResourceId) ? appServiceEnvironmentResourceId : '' clientAffinityEnabled: contains(slot, 'clientAffinityEnabled') ? slot.clientAffinityEnabled : clientAffinityEnabled - systemAssignedIdentity: contains(slot, 'systemAssignedIdentity') ? slot.systemAssignedIdentity : systemAssignedIdentity - userAssignedIdentities: contains(slot, 'userAssignedIdentities') ? slot.userAssignedIdentities : userAssignedIdentities + managedIdentities: contains(slot, 'managedIdentities') ? slot.managedIdentities : managedIdentities keyVaultAccessIdentityResourceId: contains(slot, 'keyVaultAccessIdentityResourceId') ? slot.keyVaultAccessIdentityResourceId : keyVaultAccessIdentityResourceId storageAccountRequired: contains(slot, 'storageAccountRequired') ? slot.storageAccountRequired : storageAccountRequired virtualNetworkSubnetId: contains(slot, 'virtualNetworkSubnetId') ? slot.virtualNetworkSubnetId : virtualNetworkSubnetId @@ -402,10 +398,10 @@ output slotResourceIds array = [for (slot, index) in slots: app_slots[index].out output resourceGroupName string = resourceGroup().name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(app.identity, 'principalId') ? app.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(app.identity, 'principalId') ? app.identity.principalId : '' @description('The principal ID of the system assigned identity of slots.') -output slotSystemAssignedPrincipalIds array = [for (slot, index) in slots: app_slots[index].outputs.systemAssignedPrincipalId] +output slotSystemAssignedPrincipalIds array = [for (slot, index) in slots: app_slots[index].outputs.systemAssignedMIPrincipalId] @description('The location the resource was deployed into.') output location string = app.location @@ -417,6 +413,14 @@ output defaultHostname string = app.properties.defaultHostName // 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? diff --git a/modules/web/site/main.json b/modules/web/site/main.json index d0366d2083..c313b1d0ce 100644 --- a/modules/web/site/main.json +++ b/modules/web/site/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "16589112738321066584" + "templateHash": "7527886527579756889" }, "name": "Web/Function Apps", "description": "This module deploys a Web or Function App.", "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": { @@ -414,18 +437,10 @@ "description": "Optional. The resource ID of the app service environment to use for this resource." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "keyVaultAccessIdentityResourceId": { @@ -681,8 +696,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", @@ -1115,8 +1130,7 @@ "httpsOnly": "[if(contains(parameters('slots')[copyIndex()], 'httpsOnly'), createObject('value', parameters('slots')[copyIndex()].httpsOnly), createObject('value', parameters('httpsOnly')))]", "appServiceEnvironmentResourceId": "[if(not(empty(parameters('appServiceEnvironmentResourceId'))), createObject('value', parameters('appServiceEnvironmentResourceId')), createObject('value', ''))]", "clientAffinityEnabled": "[if(contains(parameters('slots')[copyIndex()], 'clientAffinityEnabled'), createObject('value', parameters('slots')[copyIndex()].clientAffinityEnabled), createObject('value', parameters('clientAffinityEnabled')))]", - "systemAssignedIdentity": "[if(contains(parameters('slots')[copyIndex()], 'systemAssignedIdentity'), createObject('value', parameters('slots')[copyIndex()].systemAssignedIdentity), createObject('value', parameters('systemAssignedIdentity')))]", - "userAssignedIdentities": "[if(contains(parameters('slots')[copyIndex()], 'userAssignedIdentities'), createObject('value', parameters('slots')[copyIndex()].userAssignedIdentities), createObject('value', parameters('userAssignedIdentities')))]", + "managedIdentities": "[if(contains(parameters('slots')[copyIndex()], 'managedIdentities'), createObject('value', parameters('slots')[copyIndex()].managedIdentities), createObject('value', parameters('managedIdentities')))]", "keyVaultAccessIdentityResourceId": "[if(contains(parameters('slots')[copyIndex()], 'keyVaultAccessIdentityResourceId'), createObject('value', parameters('slots')[copyIndex()].keyVaultAccessIdentityResourceId), createObject('value', parameters('keyVaultAccessIdentityResourceId')))]", "storageAccountRequired": "[if(contains(parameters('slots')[copyIndex()], 'storageAccountRequired'), createObject('value', parameters('slots')[copyIndex()].storageAccountRequired), createObject('value', parameters('storageAccountRequired')))]", "virtualNetworkSubnetId": "[if(contains(parameters('slots')[copyIndex()], 'virtualNetworkSubnetId'), createObject('value', parameters('slots')[copyIndex()].virtualNetworkSubnetId), createObject('value', parameters('virtualNetworkSubnetId')))]", @@ -1163,13 +1177,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "8235549434045732740" + "templateHash": "11996079594340351559" }, "name": "Web/Function App Deployment Slots", "description": "This module deploys a Web or Function App Deployment Slot.", "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": { @@ -1578,18 +1615,10 @@ "description": "Optional. The resource ID of the app service environment to use for this resource." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "keyVaultAccessIdentityResourceId": { @@ -1824,8 +1853,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", @@ -2969,12 +2998,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), if(contains(reference('slot', '2022-09-01', 'full'), 'identity'), contains(reference('slot', '2022-09-01', 'full').identity, 'principalId'), false())), reference('slot', '2022-09-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('slot', '2022-09-01', 'full').identity, 'principalId')), reference('slot', '2022-09-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", @@ -3847,12 +3876,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('app', '2022-09-01', 'full').identity, 'principalId')), reference('app', '2022-09-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('app', '2022-09-01', 'full').identity, 'principalId')), reference('app', '2022-09-01', 'full').identity.principalId, '')]" }, "slotSystemAssignedPrincipalIds": { "type": "array", @@ -3861,7 +3890,7 @@ }, "copy": { "count": "[length(parameters('slots'))]", - "input": "[reference(format('app_slots[{0}]', copyIndex())).outputs.systemAssignedPrincipalId.value]" + "input": "[reference(format('app_slots[{0}]', copyIndex())).outputs.systemAssignedMIPrincipalId.value]" } }, "location": { diff --git a/modules/web/site/slot/README.md b/modules/web/site/slot/README.md index 2f035b876f..29258b7088 100644 --- a/modules/web/site/slot/README.md +++ b/modules/web/site/slot/README.md @@ -64,6 +64,7 @@ This module deploys a Web or Function App Deployment Slot. | [`keyVaultAccessIdentityResourceId`](#parameter-keyvaultaccessidentityresourceid) | string | The resource ID of the assigned identity to be used to access a key vault with. | | [`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. | | [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Allow or block all public traffic. | | [`redundancyMode`](#parameter-redundancymode) | string | Site redundancy mode. | @@ -73,9 +74,7 @@ This module deploys a Web or Function App Deployment Slot. | [`siteConfig`](#parameter-siteconfig) | object | The site config object. | | [`storageAccountRequired`](#parameter-storageaccountrequired) | bool | Checks if Customer provided storage account is required. | | [`storageAccountResourceId`](#parameter-storageaccountresourceid) | string | Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | | [`virtualNetworkSubnetId`](#parameter-virtualnetworksubnetid) | string | Azure Resource Manager ID of the Virtual network and subnet to be joined by Regional VNET Integration. This must be of the form /subscriptions/{subscriptionName}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{vnetName}/subnets/{subnetName}. | | [`vnetContentShareEnabled`](#parameter-vnetcontentshareenabled) | bool | To enable accessing content over virtual network. | | [`vnetImagePullEnabled`](#parameter-vnetimagepullenabled) | bool | To enable pulling image over Virtual Network. | @@ -377,6 +376,32 @@ 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` Name of the slot. @@ -670,13 +695,6 @@ Required if app of kind functionapp. Resource ID of the storage account to manag - Type: string - Default: `''` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -684,13 +702,6 @@ Tags of the resource. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ### Parameter: `virtualNetworkSubnetId` Azure Resource Manager ID of the Virtual network and subnet to be joined by Regional VNET Integration. This must be of the form /subscriptions/{subscriptionName}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{vnetName}/subnets/{subnetName}. @@ -728,7 +739,7 @@ Virtual Network Route All enabled. This causes all outbound traffic to have Virt | `name` | string | The name of the slot. | | `resourceGroupName` | string | The resource group the slot was deployed into. | | `resourceId` | string | The resource ID of the slot. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/web/site/slot/main.bicep b/modules/web/site/slot/main.bicep index 2a7719afdd..3cb7142811 100644 --- a/modules/web/site/slot/main.bicep +++ b/modules/web/site/slot/main.bicep @@ -33,11 +33,8 @@ param clientAffinityEnabled bool = true @description('Optional. The resource ID of the app service environment to use for this resource.') param appServiceEnvironmentResourceId string = '' -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. The resource ID of the assigned identity to be used to access a key vault with.') param keyVaultAccessIdentityResourceId string = '' @@ -149,11 +146,11 @@ param vnetRouteAllEnabled bool = false @description('Optional. Names of hybrid connection relays to connect app with.') param hybridConnectionRelays array = [] -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 enableReferencedModulesTelemetry = false @@ -340,7 +337,7 @@ output resourceId string = slot.id output resourceGroupName string = resourceGroup().name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && (contains(slot, 'identity') ? contains(slot.identity, 'principalId') : false) ? slot.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(slot.identity, 'principalId') ? slot.identity.principalId : '' @description('The location the resource was deployed into.') output location string = slot.location @@ -349,6 +346,14 @@ output location string = slot.location // 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? diff --git a/modules/web/site/slot/main.json b/modules/web/site/slot/main.json index b8898780c5..6ce2296e50 100644 --- a/modules/web/site/slot/main.json +++ b/modules/web/site/slot/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "8235549434045732740" + "templateHash": "11996079594340351559" }, "name": "Web/Function App Deployment Slots", "description": "This module deploys a Web or Function App Deployment Slot.", "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": { @@ -421,18 +444,10 @@ "description": "Optional. The resource ID of the app service environment to use for this resource." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "keyVaultAccessIdentityResourceId": { @@ -667,8 +682,8 @@ } }, "variables": { - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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())]", "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", @@ -1812,12 +1827,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), if(contains(reference('slot', '2022-09-01', 'full'), 'identity'), contains(reference('slot', '2022-09-01', 'full').identity, 'principalId'), false())), reference('slot', '2022-09-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('slot', '2022-09-01', 'full').identity, 'principalId')), reference('slot', '2022-09-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", diff --git a/modules/web/static-site/.test/common/main.test.bicep b/modules/web/static-site/.test/common/main.test.bicep index cd2de2ac13..4755385208 100644 --- a/modules/web/static-site/.test/common/main.test.bicep +++ b/modules/web/static-site/.test/common/main.test.bicep @@ -83,9 +83,11 @@ module testDeployment '../../main.bicep' = { ] sku: 'Standard' stagingEnvironmentPolicy: 'Enabled' - systemAssignedIdentity: true - userAssignedIdentities: { - '${nestedDependencies.outputs.managedIdentityResourceId}': {} + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] } appSettings: { foo: 'bar' diff --git a/modules/web/static-site/README.md b/modules/web/static-site/README.md index 0f632c9a57..ed4ab98af5 100644 --- a/modules/web/static-site/README.md +++ b/modules/web/static-site/README.md @@ -68,6 +68,12 @@ module staticSite 'br:bicep/modules/web.static-site:1.0.0' = { kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] + } privateEndpoints: [ { privateDnsZoneResourceIds: [ @@ -90,15 +96,11 @@ module staticSite 'br:bicep/modules/web.static-site:1.0.0' = { ] sku: 'Standard' stagingEnvironmentPolicy: 'Enabled' - systemAssignedIdentity: true tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - userAssignedIdentities: { - '': {} - } } } ``` @@ -152,6 +154,14 @@ module staticSite 'br:bicep/modules/web.static-site:1.0.0' = { "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourcesIds": [ + "" + ] + } + }, "privateEndpoints": { "value": [ { @@ -182,20 +192,12 @@ module staticSite 'br:bicep/modules/web.static-site:1.0.0' = { "stagingEnvironmentPolicy": { "value": "Enabled" }, - "systemAssignedIdentity": { - "value": true - }, "tags": { "value": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } - }, - "userAssignedIdentities": { - "value": { - "": {} - } } } } @@ -276,6 +278,7 @@ module staticSite 'br:bicep/modules/web.static-site:1.0.0' = { | [`linkedBackend`](#parameter-linkedbackend) | object | Object with "resourceId" and "location" of the a user defined function app. | | [`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. Note, requires the 'sku' to be 'Standard'. | | [`provider`](#parameter-provider) | string | The provider that submitted the last deployment to the primary environment of the static site. | | [`repositoryToken`](#parameter-repositorytoken) | securestring | The Personal Access Token for accessing the GitHub repository. | @@ -283,10 +286,8 @@ module staticSite 'br:bicep/modules/web.static-site:1.0.0' = { | [`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'. | | [`sku`](#parameter-sku) | string | Type of static site to deploy. | | [`stagingEnvironmentPolicy`](#parameter-stagingenvironmentpolicy) | string | State indicating whether staging environments are allowed or not allowed for a static web app. | -| [`systemAssignedIdentity`](#parameter-systemassignedidentity) | bool | Enables system assigned managed identity on the resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`templateProperties`](#parameter-templateproperties) | object | Template Options for the static site. | -| [`userAssignedIdentities`](#parameter-userassignedidentities) | object | The ID(s) to assign to the resource. | ### Parameter: `allowConfigFileUpdates` @@ -386,6 +387,32 @@ 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` Name of the static site. @@ -665,13 +692,6 @@ State indicating whether staging environments are allowed or not allowed for a s - Default: `'Enabled'` - Allowed: `[Disabled, Enabled]` -### Parameter: `systemAssignedIdentity` - -Enables system assigned managed identity on the resource. -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `tags` Tags of the resource. @@ -686,13 +706,6 @@ Template Options for the static site. - Type: object - Default: `{object}` -### Parameter: `userAssignedIdentities` - -The ID(s) to assign to the resource. -- Required: No -- Type: object -- Default: `{object}` - ## Outputs @@ -703,7 +716,7 @@ The ID(s) to assign to the resource. | `name` | string | The name of the static site. | | `resourceGroupName` | string | The resource group the static site was deployed into. | | `resourceId` | string | The resource ID of the static site. | -| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/modules/web/static-site/main.bicep b/modules/web/static-site/main.bicep index efe8df8ec6..181e771819 100644 --- a/modules/web/static-site/main.bicep +++ b/modules/web/static-site/main.bicep @@ -55,11 +55,8 @@ param repositoryUrl string = '' @description('Optional. The branch name of the GitHub repository.') param branch string = '' -@description('Optional. Enables system assigned managed identity on the resource.') -param systemAssignedIdentity bool = false - -@description('Optional. The ID(s) to assign to the resource.') -param userAssignedIdentities object = {} +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType @description('Optional. The lock settings of the service.') param lock lockType @@ -90,11 +87,11 @@ param customDomains array = [] var enableReferencedModulesTelemetry = false -var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') +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 = identityType != 'None' ? { - type: identityType - userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +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 = { @@ -238,7 +235,7 @@ output resourceId string = staticSite.id output resourceGroupName string = resourceGroup().name @description('The principal ID of the system assigned identity.') -output systemAssignedPrincipalId string = systemAssignedIdentity && contains(staticSite.identity, 'principalId') ? staticSite.identity.principalId : '' +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) && contains(staticSite.identity, 'principalId') ? staticSite.identity.principalId : '' @description('The location the resource was deployed into.') output location string = staticSite.location @@ -250,6 +247,14 @@ output defaultHostname string = staticSite.properties.defaultHostname // 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? diff --git a/modules/web/static-site/main.json b/modules/web/static-site/main.json index b992f8c721..b7423b7aea 100644 --- a/modules/web/static-site/main.json +++ b/modules/web/static-site/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "631543863258215268" + "templateHash": "332857934206486865" }, "name": "Static Web Apps", "description": "This module deploys a Static Web App.", "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": { @@ -354,18 +377,10 @@ "description": "Optional. The branch name of the GitHub repository." } }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. The ID(s) to assign to the resource." + "description": "Optional. The managed identity definition for this resource." } }, "lock": { @@ -431,8 +446,8 @@ }, "variables": { "enableReferencedModulesTelemetry": false, - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), 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(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')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", @@ -1600,12 +1615,12 @@ }, "value": "[resourceGroup().name]" }, - "systemAssignedPrincipalId": { + "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference('staticSite', '2021-03-01', 'full').identity, 'principalId')), reference('staticSite', '2021-03-01', 'full').identity.principalId, '')]" + "value": "[if(and(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), contains(reference('staticSite', '2021-03-01', 'full').identity, 'principalId')), reference('staticSite', '2021-03-01', 'full').identity.principalId, '')]" }, "location": { "type": "string", From 3a3d6d6fe285e34d6fd57e53045ae8a0e0b09506 Mon Sep 17 00:00:00 2001 From: CARMLPipelinePrincipal Date: Tue, 31 Oct 2023 12:18:42 +0000 Subject: [PATCH 7/7] Push updated Readme file(s) --- docs/wiki/The library - Module overview.md | 86 +++++++++++----------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/docs/wiki/The library - Module overview.md b/docs/wiki/The library - Module overview.md index a25d8ce89f..67a0adf1e7 100644 --- a/docs/wiki/The library - Module overview.md +++ b/docs/wiki/The library - Module overview.md @@ -15,9 +15,9 @@ This section provides an overview of the library's feature set. | - | - | - | - | - | - | - | - | - | - | - | | 1 | aad

domain-service | [![AAD - DomainServices](https://github.com/Azure/ResourceModules/workflows/AAD%20-%20DomainServices/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.aad.domainservices.yml) | | | :white_check_mark: | | | | | 251 | | 2 | analysis-services

server | [![AnalysisServices - Servers](https://github.com/Azure/ResourceModules/workflows/AnalysisServices%20-%20Servers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.analysisservices.servers.yml) | | | :white_check_mark: | | | | | 170 | -| 3 | api-management

service | [![ApiManagement - Service](https://github.com/Azure/ResourceModules/workflows/ApiManagement%20-%20Service/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.apimanagement.service.yml) | | | :white_check_mark: | | | | [L1:11, L2:3] | 451 | -| 4 | app-configuration

configuration-store | [![AppConfiguration - ConfigurationStores](https://github.com/Azure/ResourceModules/workflows/AppConfiguration%20-%20ConfigurationStores/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.appconfiguration.configurationstores.yml) | | | :white_check_mark: | | | | [L1:1] | 305 | -| 5 | app

container-app | [![App - ContainerApps](https://github.com/Azure/ResourceModules/workflows/App%20-%20ContainerApps/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.app.containerapps.yml) | | | :white_check_mark: | | | | | 205 | +| 3 | api-management

service | [![ApiManagement - Service](https://github.com/Azure/ResourceModules/workflows/ApiManagement%20-%20Service/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.apimanagement.service.yml) | | | :white_check_mark: | | | | [L1:11, L2:3] | 455 | +| 4 | app-configuration

configuration-store | [![AppConfiguration - ConfigurationStores](https://github.com/Azure/ResourceModules/workflows/AppConfiguration%20-%20ConfigurationStores/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.appconfiguration.configurationstores.yml) | | | :white_check_mark: | | | | [L1:1] | 309 | +| 5 | app

container-app | [![App - ContainerApps](https://github.com/Azure/ResourceModules/workflows/App%20-%20ContainerApps/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.app.containerapps.yml) | | | :white_check_mark: | | | | | 211 | | 6 | app

job | [![App - Jobs](https://github.com/Azure/ResourceModules/workflows/App%20-%20Jobs/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.app.jobs.yml) | | | :white_check_mark: | | | | | 162 | | 7 | app

managed-environment | [![App - Managed Environments](https://github.com/Azure/ResourceModules/workflows/App%20-%20Managed%20Environments/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.app.managedenvironments.yml) | | | :white_check_mark: | | | | | 163 | | 8 | authorization

lock | [![Authorization - Locks](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20Locks/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.locks.yml) | | | | | | | [L1:2] | 62 | @@ -27,44 +27,44 @@ This section provides an overview of the library's feature set. | 12 | authorization

policy-set-definition | [![Authorization - PolicySetDefinitions](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20PolicySetDefinitions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.policysetdefinitions.yml) | | | | | | | [L1:2] | 76 | | 13 | authorization

role-assignment | [![Authorization - RoleAssignments](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20RoleAssignments/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.roleassignments.yml) | | | | | | | [L1:3] | 107 | | 14 | authorization

role-definition | [![Authorization - RoleDefinitions](https://github.com/Azure/ResourceModules/workflows/Authorization%20-%20RoleDefinitions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.authorization.roledefinitions.yml) | | | | | | | [L1:3] | 94 | -| 15 | automation

automation-account | [![Automation - AutomationAccounts](https://github.com/Azure/ResourceModules/workflows/Automation%20-%20AutomationAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.automation.automationaccounts.yml) | | | :white_check_mark: | | | | [L1:6] | 437 | -| 16 | batch

batch-account | [![Batch - BatchAccounts](https://github.com/Azure/ResourceModules/workflows/Batch%20-%20BatchAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.batch.batchaccounts.yml) | | | :white_check_mark: | | | | | 311 | -| 17 | cache

redis | [![Cache - Redis](https://github.com/Azure/ResourceModules/workflows/Cache%20-%20Redis/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.cache.redis.yml) | | | :white_check_mark: | | | | | 312 | +| 15 | automation

automation-account | [![Automation - AutomationAccounts](https://github.com/Azure/ResourceModules/workflows/Automation%20-%20AutomationAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.automation.automationaccounts.yml) | | | :white_check_mark: | | | | [L1:6] | 441 | +| 16 | batch

batch-account | [![Batch - BatchAccounts](https://github.com/Azure/ResourceModules/workflows/Batch%20-%20BatchAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.batch.batchaccounts.yml) | | | :white_check_mark: | | | | | 317 | +| 17 | cache

redis | [![Cache - Redis](https://github.com/Azure/ResourceModules/workflows/Cache%20-%20Redis/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.cache.redis.yml) | | | :white_check_mark: | | | | | 318 | | 18 | cache

redis-enterprise | [![Cache - Redis Enterprise](https://github.com/Azure/ResourceModules/workflows/Cache%20-%20Redis%20Enterprise/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.cache.redisenterprise.yml) | | | :white_check_mark: | | | | [L1:1] | 268 | | 19 | cdn

profile | [![CDN - Profiles](https://github.com/Azure/ResourceModules/workflows/CDN%20-%20Profiles/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.cdn.profiles.yml) | | | :white_check_mark: | | | | [L1:6, L2:4] | 220 | -| 20 | cognitive-services

account | [![CognitiveServices - Accounts](https://github.com/Azure/ResourceModules/workflows/CognitiveServices%20-%20Accounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.cognitiveservices.accounts.yml) | | | :white_check_mark: | | | | | 375 | +| 20 | cognitive-services

account | [![CognitiveServices - Accounts](https://github.com/Azure/ResourceModules/workflows/CognitiveServices%20-%20Accounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.cognitiveservices.accounts.yml) | | | :white_check_mark: | | | | | 379 | | 21 | compute

availability-set | [![Compute - AvailabilitySets](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20AvailabilitySets/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.availabilitysets.yml) | | | :white_check_mark: | | | | | 111 | | 22 | compute

disk | [![Compute - Disks](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20Disks/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.disks.yml) | | | :white_check_mark: | | | | | 218 | -| 23 | compute

disk-encryption-set | [![Compute - DiskEncryptionSets](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20DiskEncryptionSets/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.diskencryptionsets.yml) | | | :white_check_mark: | | | | [L1:1] | 162 | +| 23 | compute

disk-encryption-set | [![Compute - DiskEncryptionSets](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20DiskEncryptionSets/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.diskencryptionsets.yml) | | | :white_check_mark: | | | | [L1:1] | 168 | | 24 | compute

gallery | [![Compute - Galleries](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20Galleries/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.galleries.yml) | | | :white_check_mark: | | | | [L1:2] | 155 | | 25 | compute

image | [![Compute - Images](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20Images/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.images.yml) | | | :white_check_mark: | | | | | 137 | | 26 | compute

proximity-placement-group | [![Compute - ProximityPlacementGroups](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20ProximityPlacementGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.proximityplacementgroups.yml) | | | :white_check_mark: | | | | | 111 | | 27 | compute

ssh-public-key | [![Compute - SshPublicKeys](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20SshPublicKeys/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.sshpublickeys.yml) | | | :white_check_mark: | | | | | 99 | -| 28 | compute

virtual-machine | [![Compute - VirtualMachines](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20VirtualMachines/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.virtualmachines.yml) | | | :white_check_mark: | | | | [L1:2] | 663 | -| 29 | compute

virtual-machine-scale-set | [![Compute - VirtualMachineScaleSets](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20VirtualMachineScaleSets/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.virtualmachinescalesets.yml) | | | :white_check_mark: | | | | [L1:1] | 607 | +| 28 | compute

virtual-machine | [![Compute - VirtualMachines](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20VirtualMachines/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.virtualmachines.yml) | | | :white_check_mark: | | | | [L1:2] | 657 | +| 29 | compute

virtual-machine-scale-set | [![Compute - VirtualMachineScaleSets](https://github.com/Azure/ResourceModules/workflows/Compute%20-%20VirtualMachineScaleSets/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.compute.virtualmachinescalesets.yml) | | | :white_check_mark: | | | | [L1:1] | 611 | | 30 | consumption

budget | [![Consumption - Budgets](https://github.com/Azure/ResourceModules/workflows/Consumption%20-%20Budgets/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.consumption.budgets.yml) | | | | | | | | 92 | -| 31 | container-instance

container-group | [![ContainerInstance - ContainerGroups](https://github.com/Azure/ResourceModules/workflows/ContainerInstance%20-%20ContainerGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.containerinstance.containergroups.yml) | | | :white_check_mark: | | | | | 163 | -| 32 | container-registry

registry | [![ContainerRegistry - Registries](https://github.com/Azure/ResourceModules/workflows/ContainerRegistry%20-%20Registries/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.containerregistry.registries.yml) | | | :white_check_mark: | | | | [L1:3] | 430 | -| 33 | container-service

managed-cluster | [![ContainerService - ManagedClusters](https://github.com/Azure/ResourceModules/workflows/ContainerService%20-%20ManagedClusters/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.containerservice.managedclusters.yml) | | | :white_check_mark: | | | | [L1:1] | 664 | -| 34 | data-factory

factory | [![DataFactory - Factories](https://github.com/Azure/ResourceModules/workflows/DataFactory%20-%20Factories/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.datafactory.factories.yml) | | | :white_check_mark: | | | | [L1:2, L2:1] | 318 | -| 35 | data-protection

backup-vault | [![DataProtection - BackupVaults](https://github.com/Azure/ResourceModules/workflows/DataProtection%20-%20BackupVaults/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.dataprotection.backupvaults.yml) | | | :white_check_mark: | | | | [L1:1] | 156 | -| 36 | databricks

access-connector | [![Databricks - Access Connectors](https://github.com/Azure/ResourceModules/workflows/Databricks%20-%20Access%20Connectors/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.databricks.accessconnectors.yml) | | | :white_check_mark: | | | | | 104 | +| 31 | container-instance

container-group | [![ContainerInstance - ContainerGroups](https://github.com/Azure/ResourceModules/workflows/ContainerInstance%20-%20ContainerGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.containerinstance.containergroups.yml) | | | :white_check_mark: | | | | | 167 | +| 32 | container-registry

registry | [![ContainerRegistry - Registries](https://github.com/Azure/ResourceModules/workflows/ContainerRegistry%20-%20Registries/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.containerregistry.registries.yml) | | | :white_check_mark: | | | | [L1:3] | 434 | +| 33 | container-service

managed-cluster | [![ContainerService - ManagedClusters](https://github.com/Azure/ResourceModules/workflows/ContainerService%20-%20ManagedClusters/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.containerservice.managedclusters.yml) | | | :white_check_mark: | | | | [L1:1] | 668 | +| 34 | data-factory

factory | [![DataFactory - Factories](https://github.com/Azure/ResourceModules/workflows/DataFactory%20-%20Factories/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.datafactory.factories.yml) | | | :white_check_mark: | | | | [L1:2, L2:1] | 322 | +| 35 | data-protection

backup-vault | [![DataProtection - BackupVaults](https://github.com/Azure/ResourceModules/workflows/DataProtection%20-%20BackupVaults/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.dataprotection.backupvaults.yml) | | | :white_check_mark: | | | | [L1:1] | 159 | +| 36 | databricks

access-connector | [![Databricks - Access Connectors](https://github.com/Azure/ResourceModules/workflows/Databricks%20-%20Access%20Connectors/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.databricks.accessconnectors.yml) | | | :white_check_mark: | | | | | 110 | | 37 | databricks

workspace | [![Databricks - Workspaces](https://github.com/Azure/ResourceModules/workflows/Databricks%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.databricks.workspaces.yml) | | | :white_check_mark: | | | | | 376 | -| 38 | db-for-my-sql

flexible-server | [![DbForMySQL - FlexibleServers](https://github.com/Azure/ResourceModules/workflows/DbForMySQL%20-%20FlexibleServers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.dbformysql.flexibleservers.yml) | | | :white_check_mark: | | | | [L1:3] | 370 | -| 39 | db-for-postgre-sql

flexible-server | [![DbForPostgreSQL - FlexibleServers](https://github.com/Azure/ResourceModules/workflows/DbForPostgreSQL%20-%20FlexibleServers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.dbforpostgresql.flexibleservers.yml) | | | :white_check_mark: | | | | [L1:4] | 364 | +| 38 | db-for-my-sql

flexible-server | [![DbForMySQL - FlexibleServers](https://github.com/Azure/ResourceModules/workflows/DbForMySQL%20-%20FlexibleServers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.dbformysql.flexibleservers.yml) | | | :white_check_mark: | | | | [L1:3] | 374 | +| 39 | db-for-postgre-sql

flexible-server | [![DbForPostgreSQL - FlexibleServers](https://github.com/Azure/ResourceModules/workflows/DbForPostgreSQL%20-%20FlexibleServers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.dbforpostgresql.flexibleservers.yml) | | | :white_check_mark: | | | | [L1:4] | 370 | | 40 | desktop-virtualization

application-group | [![DesktopVirtualization - ApplicationGroups](https://github.com/Azure/ResourceModules/workflows/DesktopVirtualization%20-%20ApplicationGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.desktopvirtualization.applicationgroups.yml) | | | :white_check_mark: | | | | [L1:1] | 191 | | 41 | desktop-virtualization

host-pool | [![DesktopVirtualization - HostPools](https://github.com/Azure/ResourceModules/workflows/DesktopVirtualization%20-%20HostPools/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.desktopvirtualization.hostpools.yml) | | | :white_check_mark: | | | | | 281 | | 42 | desktop-virtualization

scaling-plan | [![DesktopVirtualization - Scalingplans](https://github.com/Azure/ResourceModules/workflows/DesktopVirtualization%20-%20Scalingplans/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.desktopvirtualization.scalingplans.yml) | | | :white_check_mark: | | | | | 200 | | 43 | desktop-virtualization

workspace | [![DesktopVirtualization - Workspaces](https://github.com/Azure/ResourceModules/workflows/DesktopVirtualization%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.desktopvirtualization.workspaces.yml) | | | :white_check_mark: | | | | | 161 | -| 44 | dev-test-lab

lab | [![DevTestLab - Labs](https://github.com/Azure/ResourceModules/workflows/DevTestLab%20-%20Labs/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.devtestlab.labs.yml) | | | :white_check_mark: | | | | [L1:6, L2:1] | 295 | +| 44 | dev-test-lab

lab | [![DevTestLab - Labs](https://github.com/Azure/ResourceModules/workflows/DevTestLab%20-%20Labs/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.devtestlab.labs.yml) | | | :white_check_mark: | | | | [L1:6, L2:1] | 304 | | 45 | digital-twins

digital-twins-instance | [![DigitalTwins - DigitalTwinsInstances](https://github.com/Azure/ResourceModules/workflows/DigitalTwins%20-%20DigitalTwinsInstances/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.digitaltwins.digitaltwinsinstances.yml) | | | :white_check_mark: | | | | [L1:3] | 292 | -| 46 | document-db

database-account | [![DocumentDB - DatabaseAccounts](https://github.com/Azure/ResourceModules/workflows/DocumentDB%20-%20DatabaseAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.documentdb.databaseaccounts.yml) | | | :white_check_mark: | | | | [L1:3, L2:3] | 400 | +| 46 | document-db

database-account | [![DocumentDB - DatabaseAccounts](https://github.com/Azure/ResourceModules/workflows/DocumentDB%20-%20DatabaseAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.documentdb.databaseaccounts.yml) | | | :white_check_mark: | | | | [L1:3, L2:3] | 404 | | 47 | event-grid

domain | [![EventGrid - Domains](https://github.com/Azure/ResourceModules/workflows/EventGrid%20-%20Domains/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.eventgrid.domains.yml) | | | :white_check_mark: | | | | [L1:1] | 248 | -| 48 | event-grid

system-topic | [![EventGrid - System Topics](https://github.com/Azure/ResourceModules/workflows/EventGrid%20-%20System%20Topics/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.eventgrid.systemtopics.yml) | | | :white_check_mark: | | | | [L1:1] | 193 | +| 48 | event-grid

system-topic | [![EventGrid - System Topics](https://github.com/Azure/ResourceModules/workflows/EventGrid%20-%20System%20Topics/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.eventgrid.systemtopics.yml) | | | :white_check_mark: | | | | [L1:1] | 197 | | 49 | event-grid

topic | [![EventGrid - Topics](https://github.com/Azure/ResourceModules/workflows/EventGrid%20-%20Topics/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.eventgrid.topics.yml) | | | :white_check_mark: | | | | [L1:1] | 252 | -| 50 | event-hub

namespace | [![EventHub - Namespaces](https://github.com/Azure/ResourceModules/workflows/EventHub%20-%20Namespaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.eventhub.namespaces.yml) | | | :white_check_mark: | | | | [L1:4, L2:2] | 397 | -| 51 | health-bot

health-bot | [![HealthBot - HealthBots](https://github.com/Azure/ResourceModules/workflows/HealthBot%20-%20HealthBots/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.healthbot.healthbots.yml) | | | :white_check_mark: | | | | | 112 | -| 52 | healthcare-apis

workspace | [![HealthcareApis - Workspaces](https://github.com/Azure/ResourceModules/workflows/HealthcareApis%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.healthcareapis.workspaces.yml) | | | :white_check_mark: | | | | [L1:3, L2:1] | 198 | +| 50 | event-hub

namespace | [![EventHub - Namespaces](https://github.com/Azure/ResourceModules/workflows/EventHub%20-%20Namespaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.eventhub.namespaces.yml) | | | :white_check_mark: | | | | [L1:4, L2:2] | 401 | +| 51 | health-bot

health-bot | [![HealthBot - HealthBots](https://github.com/Azure/ResourceModules/workflows/HealthBot%20-%20HealthBots/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.healthbot.healthbots.yml) | | | :white_check_mark: | | | | | 116 | +| 52 | healthcare-apis

workspace | [![HealthcareApis - Workspaces](https://github.com/Azure/ResourceModules/workflows/HealthcareApis%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.healthcareapis.workspaces.yml) | | | :white_check_mark: | | | | [L1:3, L2:1] | 195 | | 53 | insights

action-group | [![Insights - ActionGroups](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20ActionGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.actiongroups.yml) | | | :white_check_mark: | | | | | 115 | | 54 | insights

activity-log-alert | [![Insights - ActivityLogAlerts](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20ActivityLogAlerts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.activitylogalerts.yml) | | | :white_check_mark: | | | | | 104 | | 55 | insights

component | [![Insights - Components](https://github.com/Azure/ResourceModules/workflows/Insights%20-%20Components/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.insights.components.yml) | | | :white_check_mark: | | | | | 184 | @@ -78,14 +78,14 @@ This section provides an overview of the library's feature set. | 63 | key-vault

vault | [![KeyVault - Vaults](https://github.com/Azure/ResourceModules/workflows/KeyVault%20-%20Vaults/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.keyvault.vaults.yml) | | | :white_check_mark: | | | | [L1:3] | 347 | | 64 | kubernetes-configuration

extension | [![KubernetesConfiguration - Extensions](https://github.com/Azure/ResourceModules/workflows/KubernetesConfiguration%20-%20Extensions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.kubernetesconfiguration.extensions.yml) | | | | | | | | 88 | | 65 | kubernetes-configuration

flux-configuration | [![KubernetesConfiguration - FluxConfigurations](https://github.com/Azure/ResourceModules/workflows/KubernetesConfiguration%20-%20FluxConfigurations/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.kubernetesconfiguration.fluxconfigurations.yml) | | | | | | | | 71 | -| 66 | logic

workflow | [![Logic - Workflows](https://github.com/Azure/ResourceModules/workflows/Logic%20-%20Workflows/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.logic.workflows.yml) | | | :white_check_mark: | | | | | 227 | -| 67 | machine-learning-services

workspace | [![MachineLearningServices - Workspaces](https://github.com/Azure/ResourceModules/workflows/MachineLearningServices%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.machinelearningservices.workspaces.yml) | | | :white_check_mark: | | | | [L1:1] | 352 | +| 66 | logic

workflow | [![Logic - Workflows](https://github.com/Azure/ResourceModules/workflows/Logic%20-%20Workflows/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.logic.workflows.yml) | | | :white_check_mark: | | | | | 231 | +| 67 | machine-learning-services

workspace | [![MachineLearningServices - Workspaces](https://github.com/Azure/ResourceModules/workflows/MachineLearningServices%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.machinelearningservices.workspaces.yml) | | | :white_check_mark: | | | | [L1:1] | 356 | | 68 | maintenance

maintenance-configuration | [![Maintenance - MaintenanceConfigurations](https://github.com/Azure/ResourceModules/workflows/Maintenance%20-%20MaintenanceConfigurations/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.maintenance.maintenanceconfigurations.yml) | | | :white_check_mark: | | | | | 136 | | 69 | managed-identity

user-assigned-identity | [![ManagedIdentity - UserAssignedIdentities](https://github.com/Azure/ResourceModules/workflows/ManagedIdentity%20-%20UserAssignedIdentities/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.managedidentity.userassignedidentities.yml) | | | :white_check_mark: | | | | [L1:1] | 113 | | 70 | managed-services

registration-definition | [![ManagedServices - RegistrationDefinitions](https://github.com/Azure/ResourceModules/workflows/ManagedServices%20-%20RegistrationDefinitions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.managedservices.registrationdefinitions.yml) | | | | | | | | 67 | | 71 | management

management-group | [![Management - ManagementGroups](https://github.com/Azure/ResourceModules/workflows/Management%20-%20ManagementGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.management.managementgroups.yml) | | | | | | | | 50 | -| 72 | net-app

net-app-account | [![NetApp - NetAppAccounts](https://github.com/Azure/ResourceModules/workflows/NetApp%20-%20NetAppAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.netapp.netappaccounts.yml) | | | :white_check_mark: | | | | [L1:1, L2:1] | 147 | -| 73 | network

application-gateway | [![Network - ApplicationGateways](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ApplicationGateways/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.applicationgateways.yml) | | | :white_check_mark: | | | | | 416 | +| 72 | net-app

net-app-account | [![NetApp - NetAppAccounts](https://github.com/Azure/ResourceModules/workflows/NetApp%20-%20NetAppAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.netapp.netappaccounts.yml) | | | :white_check_mark: | | | | [L1:1, L2:1] | 151 | +| 73 | network

application-gateway | [![Network - ApplicationGateways](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ApplicationGateways/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.applicationgateways.yml) | | | :white_check_mark: | | | | | 420 | | 74 | network

application-gateway-web-application-firewall-policy | [![Network - ApplicationGatewayWebApplicationFirewallPolicies](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ApplicationGatewayWebApplicationFirewallPolicies/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.applicationgatewaywebapplicationfirewallpolicies.yml) | | | :white_check_mark: | | | | | 47 | | 75 | network

application-security-group | [![Network - ApplicationSecurityGroups](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ApplicationSecurityGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.applicationsecuritygroups.yml) | | | :white_check_mark: | | | | | 94 | | 76 | network

azure-firewall | [![Network - AzureFirewalls](https://github.com/Azure/ResourceModules/workflows/Network%20-%20AzureFirewalls/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.azurefirewalls.yml) | | | :white_check_mark: | | | :white_check_mark: | | 335 | @@ -97,7 +97,7 @@ This section provides an overview of the library's feature set. | 82 | network

dns-zone | [![Network - Public DnsZones](https://github.com/Azure/ResourceModules/workflows/Network%20-%20Public%20DnsZones/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.dnszones.yml) | | | :white_check_mark: | | | | [L1:10] | 248 | | 83 | network

express-route-circuit | [![Network - ExpressRouteCircuits](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ExpressRouteCircuits/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.expressroutecircuits.yml) | | | :white_check_mark: | | | | | 228 | | 84 | network

express-route-gateway | [![Network - ExpressRouteGateways](https://github.com/Azure/ResourceModules/workflows/Network%20-%20ExpressRouteGateways/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.expressroutegateways.yml) | | | :white_check_mark: | | | | | 117 | -| 85 | network

firewall-policy | [![Network - FirewallPolicies](https://github.com/Azure/ResourceModules/workflows/Network%20-%20FirewallPolicies/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.firewallpolicies.yml) | | | :white_check_mark: | | | | [L1:1] | 166 | +| 85 | network

firewall-policy | [![Network - FirewallPolicies](https://github.com/Azure/ResourceModules/workflows/Network%20-%20FirewallPolicies/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.firewallpolicies.yml) | | | :white_check_mark: | | | | [L1:1] | 173 | | 86 | network

front-door | [![Network - Frontdoors](https://github.com/Azure/ResourceModules/workflows/Network%20-%20Frontdoors/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.frontdoors.yml) | | | :white_check_mark: | | | | | 181 | | 87 | network

front-door-web-application-firewall-policy | [![Network - FrontDoorWebApplicationFirewallPolicies](https://github.com/Azure/ResourceModules/workflows/Network%20-%20FrontDoorWebApplicationFirewallPolicies/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.frontdoorwebapplicationfirewallpolicies.yml) | | | :white_check_mark: | | | | | 152 | | 88 | network

ip-group | [![Network - IpGroups](https://github.com/Azure/ResourceModules/workflows/Network%20-%20IpGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.ipgroups.yml) | | | :white_check_mark: | | | | | 100 | @@ -122,35 +122,35 @@ This section provides an overview of the library's feature set. | 107 | network

virtual-wan | [![Network - VirtualWans](https://github.com/Azure/ResourceModules/workflows/Network%20-%20VirtualWans/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.virtualwans.yml) | | | :white_check_mark: | | | | | 112 | | 108 | network

vpn-gateway | [![Network - VPNGateways](https://github.com/Azure/ResourceModules/workflows/Network%20-%20VPNGateways/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.vpngateways.yml) | | | :white_check_mark: | | | | [L1:2] | 114 | | 109 | network

vpn-site | [![Network - VPN Sites](https://github.com/Azure/ResourceModules/workflows/Network%20-%20VPN%20Sites/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.network.vpnsites.yml) | | | :white_check_mark: | | | | | 124 | -| 110 | operational-insights

workspace | [![OperationalInsights - Workspaces](https://github.com/Azure/ResourceModules/workflows/OperationalInsights%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.operationalinsights.workspaces.yml) | | | :white_check_mark: | | | | [L1:7] | 344 | +| 110 | operational-insights

workspace | [![OperationalInsights - Workspaces](https://github.com/Azure/ResourceModules/workflows/OperationalInsights%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.operationalinsights.workspaces.yml) | | | :white_check_mark: | | | | [L1:7] | 348 | | 111 | operations-management

solution | [![OperationsManagement - Solutions](https://github.com/Azure/ResourceModules/workflows/OperationsManagement%20-%20Solutions/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.operationsmanagement.solutions.yml) | | | | | | | | 53 | | 112 | policy-insights

remediation | [![PolicyInsights - Remediations](https://github.com/Azure/ResourceModules/workflows/PolicyInsights%20-%20Remediations/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.policyinsights.remediations.yml) | | | | | | | [L1:3] | 106 | | 113 | power-bi-dedicated

capacity | [![PowerBiDedicated - Capacities](https://github.com/Azure/ResourceModules/workflows/PowerBiDedicated%20-%20Capacities/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.powerbidedicated.capacities.yml) | | | :white_check_mark: | | | | | 133 | -| 114 | purview

account | [![Purview - Accounts](https://github.com/Azure/ResourceModules/workflows/Purview%20-%20Accounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.purview.accounts.yml) | | | :white_check_mark: | | | | | 311 | -| 115 | recovery-services

vault | [![RecoveryServices - Vaults](https://github.com/Azure/ResourceModules/workflows/RecoveryServices%20-%20Vaults/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.recoveryservices.vaults.yml) | | | :white_check_mark: | | | | [L1:7, L2:2, L3:2] | 351 | +| 114 | purview

account | [![Purview - Accounts](https://github.com/Azure/ResourceModules/workflows/Purview%20-%20Accounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.purview.accounts.yml) | | | :white_check_mark: | | | | | 315 | +| 115 | recovery-services

vault | [![RecoveryServices - Vaults](https://github.com/Azure/ResourceModules/workflows/RecoveryServices%20-%20Vaults/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.recoveryservices.vaults.yml) | | | :white_check_mark: | | | | [L1:7, L2:2, L3:2] | 355 | | 116 | relay

namespace | [![Relay - Namespaces](https://github.com/Azure/ResourceModules/workflows/Relay%20-%20Namespaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.relay.namespaces.yml) | | | :white_check_mark: | | | | [L1:4, L2:2] | 330 | | 117 | resource-graph

query | [![ResourceGraph - Queries](https://github.com/Azure/ResourceModules/workflows/ResourceGraph%20-%20Queries/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.resourcegraph.queries.yml) | | | :white_check_mark: | | | | | 101 | -| 118 | resources

deployment-script | [![Resources - DeploymentScripts](https://github.com/Azure/ResourceModules/workflows/Resources%20-%20DeploymentScripts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.resources.deploymentscripts.yml) | | | :white_check_mark: | | | | | 128 | +| 118 | resources

deployment-script | [![Resources - DeploymentScripts](https://github.com/Azure/ResourceModules/workflows/Resources%20-%20DeploymentScripts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.resources.deploymentscripts.yml) | | | :white_check_mark: | | | | | 132 | | 119 | resources

resource-group | [![Resources - ResourceGroups](https://github.com/Azure/ResourceModules/workflows/Resources%20-%20ResourceGroups/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.resources.resourcegroups.yml) | | | :white_check_mark: | | | | [L1:1] | 101 | | 120 | resources

tags | [![Resources - Tags](https://github.com/Azure/ResourceModules/workflows/Resources%20-%20Tags/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.resources.tags.yml) | | | :white_check_mark: | | | | [L1:2] | 54 | -| 121 | search

search-service | [![Search - SearchServices](https://github.com/Azure/ResourceModules/workflows/Search%20-%20SearchServices/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.search.searchservices.yml) | | | :white_check_mark: | | | | [L1:1] | 313 | +| 121 | search

search-service | [![Search - SearchServices](https://github.com/Azure/ResourceModules/workflows/Search%20-%20SearchServices/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.search.searchservices.yml) | | | :white_check_mark: | | | | [L1:1] | 318 | | 122 | security

azure-security-center | [![Security - AzureSecurityCenter](https://github.com/Azure/ResourceModules/workflows/Security%20-%20AzureSecurityCenter/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.security.azuresecuritycenter.yml) | | | | | | | | 221 | -| 123 | service-bus

namespace | [![ServiceBus - Namespaces](https://github.com/Azure/ResourceModules/workflows/ServiceBus%20-%20Namespaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.servicebus.namespaces.yml) | | | :white_check_mark: | | | | [L1:6, L2:2] | 441 | +| 123 | service-bus

namespace | [![ServiceBus - Namespaces](https://github.com/Azure/ResourceModules/workflows/ServiceBus%20-%20Namespaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.servicebus.namespaces.yml) | | | :white_check_mark: | | | | [L1:6, L2:2] | 445 | | 124 | service-fabric

cluster | [![ServiceFabric - Clusters](https://github.com/Azure/ResourceModules/workflows/ServiceFabric%20-%20Clusters/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.servicefabric.clusters.yml) | | | :white_check_mark: | | | | [L1:1] | 312 | | 125 | signal-r-service

signal-r | [![SignalRService - SignalR](https://github.com/Azure/ResourceModules/workflows/SignalRService%20-%20SignalR/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.signalrservice.signalr.yml) | | | :white_check_mark: | | | | | 268 | -| 126 | signal-r-service

web-pub-sub | [![SignalRService - WebPubSub](https://github.com/Azure/ResourceModules/workflows/SignalRService%20-%20WebPubSub/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.signalrservice.webpubsub.yml) | | | :white_check_mark: | | | | | 238 | -| 127 | sql

managed-instance | [![Sql - ManagedInstances](https://github.com/Azure/ResourceModules/workflows/Sql%20-%20ManagedInstances/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.sql.managedinstances.yml) | | | :white_check_mark: | | | | [L1:6, L2:3] | 369 | -| 128 | sql

server | [![Sql - Servers](https://github.com/Azure/ResourceModules/workflows/Sql%20-%20Servers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.sql.servers.yml) | | | :white_check_mark: | | | | [L1:8, L2:3] | 376 | -| 129 | storage

storage-account | [![Storage - StorageAccounts](https://github.com/Azure/ResourceModules/workflows/Storage%20-%20StorageAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.storage.storageaccounts.yml) | | | :white_check_mark: | | | | [L1:6, L2:4, L3:1] | 500 | +| 126 | signal-r-service

web-pub-sub | [![SignalRService - WebPubSub](https://github.com/Azure/ResourceModules/workflows/SignalRService%20-%20WebPubSub/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.signalrservice.webpubsub.yml) | | | :white_check_mark: | | | | | 244 | +| 127 | sql

managed-instance | [![Sql - ManagedInstances](https://github.com/Azure/ResourceModules/workflows/Sql%20-%20ManagedInstances/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.sql.managedinstances.yml) | | | :white_check_mark: | | | | [L1:6, L2:3] | 373 | +| 128 | sql

server | [![Sql - Servers](https://github.com/Azure/ResourceModules/workflows/Sql%20-%20Servers/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.sql.servers.yml) | | | :white_check_mark: | | | | [L1:8, L2:3] | 380 | +| 129 | storage

storage-account | [![Storage - StorageAccounts](https://github.com/Azure/ResourceModules/workflows/Storage%20-%20StorageAccounts/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.storage.storageaccounts.yml) | | | :white_check_mark: | | | | [L1:6, L2:4, L3:1] | 504 | | 130 | synapse

private-link-hub | [![Synapse - PrivateLinkHubs](https://github.com/Azure/ResourceModules/workflows/Synapse%20-%20PrivateLinkHubs/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.synapse.privatelinkhubs.yml) | | | :white_check_mark: | | | | | 162 | | 131 | synapse

workspace | [![Synapse - Workspaces](https://github.com/Azure/ResourceModules/workflows/Synapse%20-%20Workspaces/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.synapse.workspaces.yml) | | | :white_check_mark: | | | | [L1:3] | 355 | | 132 | virtual-machine-images

image-template | [![VirtualMachineImages - ImageTemplates](https://github.com/Azure/ResourceModules/workflows/VirtualMachineImages%20-%20ImageTemplates/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.virtualmachineimages.imagetemplates.yml) | | | :white_check_mark: | | | | | 216 | | 133 | web

connection | [![Web - Connections](https://github.com/Azure/ResourceModules/workflows/Web%20-%20Connections/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.connections.yml) | | | :white_check_mark: | | | | | 118 | -| 134 | web

hosting-environment | [![Web - HostingEnvironments](https://github.com/Azure/ResourceModules/workflows/Web%20-%20HostingEnvironments/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.hostingenvironments.yml) | | | :white_check_mark: | | | | [L1:2] | 258 | +| 134 | web

hosting-environment | [![Web - HostingEnvironments](https://github.com/Azure/ResourceModules/workflows/Web%20-%20HostingEnvironments/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.hostingenvironments.yml) | | | :white_check_mark: | | | | [L1:2] | 262 | | 135 | web

serverfarm | [![Web - Serverfarms](https://github.com/Azure/ResourceModules/workflows/Web%20-%20Serverfarms/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.serverfarms.yml) | | | :white_check_mark: | | | | | 194 | -| 136 | web

site | [![Web - Sites](https://github.com/Azure/ResourceModules/workflows/Web%20-%20Sites/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.sites.yml) | | | :white_check_mark: | | | | [L1:5, L2:4, L3:1] | 441 | -| 137 | web

static-site | [![Web - StaticSites](https://github.com/Azure/ResourceModules/workflows/Web%20-%20StaticSites/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.staticsites.yml) | | | :white_check_mark: | | | | [L1:3] | 271 | -| Sum | | | 0 | 0 | 119 | 0 | 0 | 2 | 240 | 29361 | +| 136 | web

site | [![Web - Sites](https://github.com/Azure/ResourceModules/workflows/Web%20-%20Sites/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.sites.yml) | | | :white_check_mark: | | | | [L1:5, L2:4, L3:1] | 444 | +| 137 | web

static-site | [![Web - StaticSites](https://github.com/Azure/ResourceModules/workflows/Web%20-%20StaticSites/badge.svg)](https://github.com/Azure/ResourceModules/actions/workflows/ms.web.staticsites.yml) | | | :white_check_mark: | | | | [L1:3] | 275 | +| Sum | | | 0 | 0 | 119 | 0 | 0 | 2 | 240 | 29533 | ## Legend