From b11b588ffdcc87074795542b08422951f6e974fc Mon Sep 17 00:00:00 2001 From: MrMCake Date: Thu, 5 May 2022 17:57:27 +0200 Subject: [PATCH 1/5] First draft --- .../.bicep/nested_privateEndpoint.bicep | 58 +++++++++++++++++++ arm/Microsoft.Sql/servers/deploy.bicep | 17 ++++++ 2 files changed, 75 insertions(+) create mode 100644 arm/Microsoft.Sql/servers/.bicep/nested_privateEndpoint.bicep diff --git a/arm/Microsoft.Sql/servers/.bicep/nested_privateEndpoint.bicep b/arm/Microsoft.Sql/servers/.bicep/nested_privateEndpoint.bicep new file mode 100644 index 0000000000..977f3cb438 --- /dev/null +++ b/arm/Microsoft.Sql/servers/.bicep/nested_privateEndpoint.bicep @@ -0,0 +1,58 @@ +@description('The resource ID of the service to link to') +param privateEndpointResourceId string + +@description('Required. The location of the proviate endpoint') +param privateEndpointVnetLocation string + +@description('Optional. Tags to add to the private endpoint.') +param tags object = {} + +@description('Optional. The name of the private endpoint') +param name string = '${last(split(privateEndpointResourceId, '/'))}-${service}' + +@description('Required. The service/groupId his private endpoint should connect to') +param service string + +@description('Required. Subnet in a virtual network resource.') +param subnetResourceId string + +@description('Optional. Custom DNS configurations.') +param customDnsConfigs array = [] + +@description('Optional. A collection of private DNS zone configurations of the private dns zone group.') +param privateDnsZoneResourceIds array = [] + +resource privateEndpoint 'Microsoft.Network/privateEndpoints@2021-05-01' = { + name: name + location: privateEndpointVnetLocation + tags: tags + properties: { + privateLinkServiceConnections: [ + { + name: name + properties: { + privateLinkServiceId: privateEndpointResourceId + groupIds: [ + service + ] + } + } + ] + subnet: { + id: subnetResourceId + } + customDnsConfigs: customDnsConfigs + } + + resource privateDnsZoneGroups 'privateDnsZoneGroups@2021-02-01' = { + name: 'default' + properties: { + privateDnsZoneConfigs: [for privateDnsZoneResourceId in privateDnsZoneResourceIds: { + name: last(split(privateDnsZoneResourceId, '/')) + properties: { + privateDnsZoneId: privateDnsZoneResourceId + } + }] + } + } +} diff --git a/arm/Microsoft.Sql/servers/deploy.bicep b/arm/Microsoft.Sql/servers/deploy.bicep index eb6605c9f8..6da774216d 100644 --- a/arm/Microsoft.Sql/servers/deploy.bicep +++ b/arm/Microsoft.Sql/servers/deploy.bicep @@ -46,6 +46,9 @@ param securityAlertPolicies array = [] @description('Optional. The Azure Active Directory (AAD) administrator authentication. Required if no `administratorLogin` & `administratorLoginPassword` is provided.') param administrators object = {} +@description('Optional. Configuration Details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints array = [] + var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') var identity = identityType != 'None' ? { @@ -140,6 +143,20 @@ module server_databases 'databases/deploy.bicep' = [for (database, index) in dat } }] +module server_privateEndpoints '.bicep/nested_privateEndpoint.bicep' = [for (endpoint, index) in privateEndpoints: if (!empty(privateEndpoints)) { + name: '${uniqueString(deployment().name, location)}-Sql-PrivateEndpoints-${index}' + params: { + privateEndpointResourceId: server.id + privateEndpointVnetLocation: !empty(privateEndpoints) ? reference(split(endpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location : 'dummy' + service: 'sql' + subnetResourceId: endpoint.subnetResourceId + customDnsConfigs: contains(endpoint, 'customDnsConfigs') ? endpoint.customDnsConfigs : [] + name: contains(endpoint, 'name') ? endpoint.name : '${last(split(server.id, '/'))}-sql' + privateDnsZoneResourceIds: contains(endpoint, 'privateDnsZoneResourceIds') ? endpoint.privateDnsZoneResourceIds : [] + tags: contains(endpoint, 'tags') ? endpoint.tags : {} + } +}] + module server_firewallRules 'firewallRules/deploy.bicep' = [for (firewallRule, index) in firewallRules: { name: '${uniqueString(deployment().name, location)}-Sql-FirewallRules-${index}' params: { From e78411cd62f71bb36be3d0bd93600e0a6ac8fbc1 Mon Sep 17 00:00:00 2001 From: MrMCake Date: Fri, 6 May 2022 16:36:44 +0200 Subject: [PATCH 2/5] Added private endpoint --- .../servers/.bicep/nested_privateEndpoint.bicep | 2 +- arm/Microsoft.Sql/servers/.parameters/parameters.json | 7 +++++++ arm/Microsoft.Sql/servers/deploy.bicep | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/arm/Microsoft.Sql/servers/.bicep/nested_privateEndpoint.bicep b/arm/Microsoft.Sql/servers/.bicep/nested_privateEndpoint.bicep index 977f3cb438..7af99c7273 100644 --- a/arm/Microsoft.Sql/servers/.bicep/nested_privateEndpoint.bicep +++ b/arm/Microsoft.Sql/servers/.bicep/nested_privateEndpoint.bicep @@ -11,7 +11,7 @@ param tags object = {} param name string = '${last(split(privateEndpointResourceId, '/'))}-${service}' @description('Required. The service/groupId his private endpoint should connect to') -param service string +param service string = 'sqlServer' @description('Required. Subnet in a virtual network resource.') param subnetResourceId string diff --git a/arm/Microsoft.Sql/servers/.parameters/parameters.json b/arm/Microsoft.Sql/servers/.parameters/parameters.json index 2c5e6acb9f..dd78a8b64b 100644 --- a/arm/Microsoft.Sql/servers/.parameters/parameters.json +++ b/arm/Microsoft.Sql/servers/.parameters/parameters.json @@ -78,6 +78,13 @@ "value": { "/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001": {} } + }, + "privateEndpoints": { + "value": [ + { + "subnetResourceId": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/adp-<>-az-vnet-x-001/subnets/<>-az-subnet-x-005-privateEndpoints" + } + ] } } } diff --git a/arm/Microsoft.Sql/servers/deploy.bicep b/arm/Microsoft.Sql/servers/deploy.bicep index 6da774216d..2e2ec0277a 100644 --- a/arm/Microsoft.Sql/servers/deploy.bicep +++ b/arm/Microsoft.Sql/servers/deploy.bicep @@ -148,7 +148,7 @@ module server_privateEndpoints '.bicep/nested_privateEndpoint.bicep' = [for (end params: { privateEndpointResourceId: server.id privateEndpointVnetLocation: !empty(privateEndpoints) ? reference(split(endpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location : 'dummy' - service: 'sql' + service: contains(endpoint, 'service') ? endpoint.service : 'sqlServer' subnetResourceId: endpoint.subnetResourceId customDnsConfigs: contains(endpoint, 'customDnsConfigs') ? endpoint.customDnsConfigs : [] name: contains(endpoint, 'name') ? endpoint.name : '${last(split(server.id, '/'))}-sql' From 393fa5f2e97195d64baeb9e5b0530b4b8e68f0ae Mon Sep 17 00:00:00 2001 From: MrMCake Date: Fri, 6 May 2022 17:43:14 +0200 Subject: [PATCH 3/5] Updated readme --- .../tools/moduleReadMeSource/resourceUsage-privateEndpoints.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utilities/tools/moduleReadMeSource/resourceUsage-privateEndpoints.md b/utilities/tools/moduleReadMeSource/resourceUsage-privateEndpoints.md index b087c07fbe..81f6260a0d 100644 --- a/utilities/tools/moduleReadMeSource/resourceUsage-privateEndpoints.md +++ b/utilities/tools/moduleReadMeSource/resourceUsage-privateEndpoints.md @@ -10,7 +10,7 @@ To use Private Endpoint the following dependencies must be deployed: { "name": "sxx-az-pe", // Optional: Name will be automatically generated if one is not provided here "subnetResourceId": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/sxx-az-vnet-x-001/subnets/sxx-az-subnet-x-001", - "service": "<>" // e.g. vault, registry, file, blob, queue, table etc. + "service": "<>", // e.g. vault, registry, file, blob, queue, table etc. "privateDnsZoneResourceIds": [ // Optional: No DNS record will be created if a private DNS zone Resource ID is not specified "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/privateDnsZones/privatelink.blob.core.windows.net" ], From 48e6699aab7121b5417203890c70e558647bc9b5 Mon Sep 17 00:00:00 2001 From: MrMCake Date: Fri, 6 May 2022 17:49:09 +0200 Subject: [PATCH 4/5] Update to latest --- arm/Microsoft.Sql/servers/readme.md | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/arm/Microsoft.Sql/servers/readme.md b/arm/Microsoft.Sql/servers/readme.md index d2f556b73b..b9b64dd1ee 100644 --- a/arm/Microsoft.Sql/servers/readme.md +++ b/arm/Microsoft.Sql/servers/readme.md @@ -15,6 +15,8 @@ This module deploys a SQL server. | `Microsoft.Authorization/locks` | [2017-04-01](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2017-04-01/locks) | | `Microsoft.Authorization/roleAssignments` | [2020-10-01-preview](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-10-01-preview/roleAssignments) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/privateEndpoints` | [2021-05-01](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Network/2021-05-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2021-02-01](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Network/2021-02-01/privateEndpoints/privateDnsZoneGroups) | | `Microsoft.Sql/servers` | [2021-05-01-preview](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Sql/2021-05-01-preview/servers) | | `Microsoft.Sql/servers/databases` | [2021-02-01-preview](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Sql/2021-02-01-preview/servers/databases) | | `Microsoft.Sql/servers/firewallRules` | [2021-05-01-preview](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Sql/2021-05-01-preview/servers/firewallRules) | @@ -38,6 +40,7 @@ This module deploys a SQL server. | `firewallRules` | _[firewallRules](firewallRules/readme.md)_ array | `[]` | | The firewall rules to create in the server | | `location` | string | `[resourceGroup().location]` | | Location for all resources. | | `lock` | string | `'NotSpecified'` | `[CanNotDelete, NotSpecified, ReadOnly]` | Specify the type of lock. | +| `privateEndpoints` | array | `[]` | | Configuration Details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | | `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` | _[securityAlertPolicies](securityAlertPolicies/readme.md)_ array | `[]` | | The security alert policies to create in the server | | `systemAssignedIdentity` | bool | `False` | | Enables system assigned managed identity on the resource. | @@ -118,6 +121,42 @@ https://docs.microsoft.com/en-us/azure/templates/microsoft.sql/servers/administr } ``` +### Parameter Usage: `privateEndpoints` + +To use Private Endpoint the following dependencies must be deployed: + +- Destination subnet must be created with the following configuration option - `"privateEndpointNetworkPolicies": "Disabled"`. Setting this option acknowledges that NSG rules are not applied to Private Endpoints (this capability is coming soon). A full example is available in the Virtual Network Module. +- Although not strictly required, it is highly recommended to first create a private DNS Zone to host Private Endpoint DNS records. See [Azure Private Endpoint DNS configuration](https://docs.microsoft.com/en-us/azure/private-link/private-endpoint-dns) for more information. + +```json +"privateEndpoints": { + "value": [ + // Example showing all available fields + { + "name": "sxx-az-pe", // Optional: Name will be automatically generated if one is not provided here + "subnetResourceId": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/sxx-az-vnet-x-001/subnets/sxx-az-subnet-x-001", + "service": "<>", // e.g. vault, registry, file, blob, queue, table etc. + "privateDnsZoneResourceIds": [ // Optional: No DNS record will be created if a private DNS zone Resource ID is not specified + "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/privateDnsZones/privatelink.blob.core.windows.net" + ], + "customDnsConfigs": [ // Optional + { + "fqdn": "customname.test.local", + "ipAddresses": [ + "10.10.10.10" + ] + } + ] + }, + // Example showing only mandatory fields + { + "subnetResourceId": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/sxx-az-vnet-x-001/subnets/sxx-az-subnet-x-001", + "service": "<>" // e.g. vault, registry, file, blob, queue, table etc. + } + ] +} +``` + ## Outputs | Output Name | Type | Description | From fcdce287328da13a34523a4de11238a71431411c Mon Sep 17 00:00:00 2001 From: MrMCake Date: Fri, 6 May 2022 18:26:35 +0200 Subject: [PATCH 5/5] Update to latest --- arm/Microsoft.Sql/servers/readme.md | 2 +- .../tools/moduleReadMeSource/resourceUsage-privateEndpoints.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arm/Microsoft.Sql/servers/readme.md b/arm/Microsoft.Sql/servers/readme.md index b9b64dd1ee..63bd6f84e2 100644 --- a/arm/Microsoft.Sql/servers/readme.md +++ b/arm/Microsoft.Sql/servers/readme.md @@ -135,7 +135,7 @@ To use Private Endpoint the following dependencies must be deployed: { "name": "sxx-az-pe", // Optional: Name will be automatically generated if one is not provided here "subnetResourceId": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/sxx-az-vnet-x-001/subnets/sxx-az-subnet-x-001", - "service": "<>", // e.g. vault, registry, file, blob, queue, table etc. + "service": "<>" // e.g. vault, registry, file, blob, queue, table etc. "privateDnsZoneResourceIds": [ // Optional: No DNS record will be created if a private DNS zone Resource ID is not specified "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/privateDnsZones/privatelink.blob.core.windows.net" ], diff --git a/utilities/tools/moduleReadMeSource/resourceUsage-privateEndpoints.md b/utilities/tools/moduleReadMeSource/resourceUsage-privateEndpoints.md index 81f6260a0d..b087c07fbe 100644 --- a/utilities/tools/moduleReadMeSource/resourceUsage-privateEndpoints.md +++ b/utilities/tools/moduleReadMeSource/resourceUsage-privateEndpoints.md @@ -10,7 +10,7 @@ To use Private Endpoint the following dependencies must be deployed: { "name": "sxx-az-pe", // Optional: Name will be automatically generated if one is not provided here "subnetResourceId": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/sxx-az-vnet-x-001/subnets/sxx-az-subnet-x-001", - "service": "<>", // e.g. vault, registry, file, blob, queue, table etc. + "service": "<>" // e.g. vault, registry, file, blob, queue, table etc. "privateDnsZoneResourceIds": [ // Optional: No DNS record will be created if a private DNS zone Resource ID is not specified "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/privateDnsZones/privatelink.blob.core.windows.net" ],