diff --git a/.github/workflows/ms.sql.managedinstances.yml b/.github/workflows/ms.sql.managedinstances.yml index 278e6a3b27..f67dbe83a1 100644 --- a/.github/workflows/ms.sql.managedinstances.yml +++ b/.github/workflows/ms.sql.managedinstances.yml @@ -106,8 +106,7 @@ jobs: - name: 'Using test file [${{ matrix.moduleTestFilePaths }}]' uses: ./.github/actions/templates/validateModuleDeployment with: - templateFilePath: '${{ env.modulePath }}/deploy.bicep' - parameterFilePath: '${{ env.modulePath }}/${{ matrix.moduleTestFilePaths }}' + templateFilePath: '${{ env.modulePath }}/${{ matrix.moduleTestFilePaths }}' location: '${{ env.location }}' resourceGroupName: '${{ env.resourceGroupName }}' subscriptionId: '${{ secrets.ARM_SUBSCRIPTION_ID }}' diff --git a/modules/Microsoft.Sql/managedInstances/.test/common/dependencies.bicep b/modules/Microsoft.Sql/managedInstances/.test/common/dependencies.bicep new file mode 100644 index 0000000000..2b12c654c5 --- /dev/null +++ b/modules/Microsoft.Sql/managedInstances/.test/common/dependencies.bicep @@ -0,0 +1,350 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Network Security Group to create.') +param networkSecurityGroupName string + +@description('Required. The name of the Route Table to create.') +param routeTableName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +var sqlMiVnetAddressPrefix = '10.0.0.0/16' +var sqlMiSubnetAddressPrefix = '10.0.0.0/24' +var sqlMiSubnetAddressPrefixString = replace(replace(sqlMiSubnetAddressPrefix, '.', '-'), '/', '-') + +resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2021-08-01' = { + name: networkSecurityGroupName + location: location + properties: { + securityRules: [ + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-sqlmgmt-in-${sqlMiSubnetAddressPrefixString}-v10' + properties: { + description: 'Allow MI provisioning Control Plane Deployment and Authentication Service' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: 'SqlManagement' + destinationAddressPrefix: sqlMiSubnetAddressPrefix + access: 'Allow' + priority: 100 + direction: 'Inbound' + destinationPortRanges: [ + '9000' + '9003' + '1438' + '1440' + '1452' + ] + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-corpsaw-in-${sqlMiSubnetAddressPrefixString}-v10' + properties: { + description: 'Allow MI Supportability' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: 'CorpNetSaw' + destinationAddressPrefix: sqlMiSubnetAddressPrefix + access: 'Allow' + priority: 101 + direction: 'Inbound' + destinationPortRanges: [ + '9000' + '9003' + '1440' + ] + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-corppublic-in-${sqlMiSubnetAddressPrefixString}-v10' + properties: { + description: 'Allow MI Supportability through Corpnet ranges' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: 'CorpNetPublic' + destinationAddressPrefix: sqlMiSubnetAddressPrefix + access: 'Allow' + priority: 102 + direction: 'Inbound' + destinationPortRanges: [ + '9000' + '9003' + ] + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-healthprobe-in-${sqlMiSubnetAddressPrefixString}-v10' + properties: { + description: 'Allow Azure Load Balancer inbound traffic' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: 'AzureLoadBalancer' + destinationAddressPrefix: sqlMiSubnetAddressPrefix + access: 'Allow' + priority: 103 + direction: 'Inbound' + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-internal-in-${sqlMiSubnetAddressPrefixString}-v10' + properties: { + description: 'Allow MI internal inbound traffic' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: sqlMiSubnetAddressPrefix + destinationAddressPrefix: sqlMiSubnetAddressPrefix + access: 'Allow' + priority: 104 + direction: 'Inbound' + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-services-out-${sqlMiSubnetAddressPrefixString}-v10' + properties: { + description: 'Allow MI services outbound traffic over https' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: sqlMiSubnetAddressPrefix + destinationAddressPrefix: 'AzureCloud' + access: 'Allow' + priority: 100 + direction: 'Outbound' + destinationPortRanges: [ + '443' + '12000' + ] + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-internal-out-${sqlMiSubnetAddressPrefixString}-v10' + properties: { + description: 'Allow MI internal outbound traffic' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: sqlMiSubnetAddressPrefix + destinationAddressPrefix: sqlMiSubnetAddressPrefix + access: 'Allow' + priority: 101 + direction: 'Outbound' + } + } + ] + } +} + +resource routeTable 'Microsoft.Network/routeTables@2021-08-01' = { + name: routeTableName + location: location + properties: { + disableBgpRoutePropagation: false + routes: [ + { + name: 'Microsoft.Sql-managedInstances_UseOnly_subnet-${sqlMiSubnetAddressPrefixString}-to-vnetlocal' + properties: { + addressPrefix: sqlMiSubnetAddressPrefix + nextHopType: 'VnetLocal' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-Storage' + properties: { + addressPrefix: 'Storage' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-SqlManagement' + properties: { + addressPrefix: 'SqlManagement' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-AzureMonitor' + properties: { + addressPrefix: 'AzureMonitor' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-CorpNetSaw' + properties: { + addressPrefix: 'CorpNetSaw' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-CorpNetPublic' + properties: { + addressPrefix: 'CorpNetPublic' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-AzureActiveDirectory' + properties: { + addressPrefix: 'AzureActiveDirectory' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-AzureCloud.westeurope' + properties: { + addressPrefix: 'AzureCloud.westeurope' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-AzureCloud.northeurope' + properties: { + addressPrefix: 'AzureCloud.northeurope' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-Storage.westeurope' + properties: { + addressPrefix: 'Storage.westeurope' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-Storage.northeurope' + properties: { + addressPrefix: 'Storage.northeurope' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-EventHub.westeurope' + properties: { + addressPrefix: 'EventHub.westeurope' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-EventHub.northeurope' + properties: { + addressPrefix: 'EventHub.northeurope' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + ] + } +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2022-01-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + sqlMiVnetAddressPrefix + ] + } + subnets: [ + { + name: 'ManagedInstance' + properties: { + addressPrefix: sqlMiSubnetAddressPrefix + routeTable: { + id: routeTable.id + } + networkSecurityGroup: { + id: networkSecurityGroup.id + } + delegations: [ + { + name: 'managedInstanceDelegation' + properties: { + serviceName: 'Microsoft.Sql/managedInstances' + } + } + ] + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: null + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'keyEncryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource keyPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault::key.id}-${location}-${managedIdentity.id}-Key-Reader-RoleAssignment') + scope: keyVault::key + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6') // Key Vault Crypto Service Encryption User + principalType: 'ServicePrincipal' + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The URL of the created Key Vault Encryption Key.') +output keyVaultEncryptionKeyUrl string = keyVault::key.properties.keyUriWithVersion + +@description('The name of the created Key Vault Encryption Key.') +output keyVaultKeyName string = keyVault::key.name + +@description('The name of the created Key Vault.') +output keyVaultName string = keyVault.name diff --git a/modules/Microsoft.Sql/managedInstances/.test/common/deploy.test.bicep b/modules/Microsoft.Sql/managedInstances/.test/common/deploy.test.bicep new file mode 100644 index 0000000000..104f28616f --- /dev/null +++ b/modules/Microsoft.Sql/managedInstances/.test/common/deploy.test.bicep @@ -0,0 +1,139 @@ +targetScope = 'subscription' + +// ========== // +// Parameters // +// ========== // +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(80) +param resourceGroupName string = 'ms.sql.managedinstances-${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 = 'sqlmicom' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module resourceGroupResources 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + keyVaultName: 'dep-<>-kv-${serviceShort}' + managedIdentityName: 'dep-<>-msi-${serviceShort}' + virtualNetworkName: 'dep-<>-vnet-${serviceShort}' + networkSecurityGroupName: 'dep-<>-nsg-${serviceShort}' + routeTableName: 'dep-<>-rt-${serviceShort}' + location: location + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../.shared/dependencyConstructs/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-diagnosticDependencies' + params: { + storageAccountName: 'dep<>azsa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-<>-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-<>-evh-${serviceShort}' + eventHubNamespaceName: 'dep-<>-evhns-${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../deploy.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + name: '<>-${serviceShort}' + administratorLogin: 'adminUserName' + administratorLoginPassword: password + subnetId: resourceGroupResources.outputs.subnetResourceId + collation: 'SQL_Latin1_General_CP1_CI_AS' + databases: [ + { + backupLongTermRetentionPolicies: { + name: 'default' + } + backupShortTermRetentionPolicies: { + name: 'default' + } + name: '<>-${serviceShort}-db-001' + } + ] + diagnosticLogsRetentionInDays: 7 + diagnosticStorageAccountId: diagnosticDependencies.outputs.storageAccountResourceId + diagnosticWorkspaceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + diagnosticEventHubAuthorizationRuleId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + diagnosticEventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + dnsZonePartner: '' + encryptionProtectorObj: { + serverKeyName: '${resourceGroupResources.outputs.keyVaultName}_${resourceGroupResources.outputs.keyVaultKeyName}_${last(split(resourceGroupResources.outputs.keyVaultEncryptionKeyUrl, '/'))}' + serverKeyType: 'AzureKeyVault' + } + hardwareFamily: 'Gen5' + keys: [ + { + name: '${resourceGroupResources.outputs.keyVaultName}_${resourceGroupResources.outputs.keyVaultKeyName}_${last(split(resourceGroupResources.outputs.keyVaultEncryptionKeyUrl, '/'))}' + serverKeyType: 'AzureKeyVault' + uri: resourceGroupResources.outputs.keyVaultEncryptionKeyUrl + } + ] + licenseType: 'LicenseIncluded' + lock: 'CanNotDelete' + primaryUserAssignedIdentityId: resourceGroupResources.outputs.managedIdentityResourceId + proxyOverride: 'Proxy' + publicDataEndpointEnabled: false + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalIds: [ + resourceGroupResources.outputs.managedIdentityPrincipalId + ] + } + ] + securityAlertPoliciesObj: { + emailAccountAdmins: true + name: 'default' + state: 'Enabled' + } + servicePrincipal: 'SystemAssigned' + skuName: 'GP_Gen5' + skuTier: 'GeneralPurpose' + storageSizeInGB: 32 + systemAssignedIdentity: true + timezoneId: 'UTC' + userAssignedIdentities: { + '${resourceGroupResources.outputs.managedIdentityResourceId}': {} + } + vCores: 4 + vulnerabilityAssessmentsObj: { + emailSubscriptionAdmins: true + name: 'default' + recurringScansEmails: [ + 'test1@contoso.com' + 'test2@contoso.com' + ] + recurringScansIsEnabled: true + vulnerabilityAssessmentsStorageAccountId: diagnosticDependencies.outputs.storageAccountResourceId + } + } +} diff --git a/modules/Microsoft.Sql/managedInstances/.test/min.parameters.json b/modules/Microsoft.Sql/managedInstances/.test/min.parameters.json deleted file mode 100644 index 04f1025064..0000000000 --- a/modules/Microsoft.Sql/managedInstances/.test/min.parameters.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "name": { - "value": "<>-az-sqlmi-min-001" - }, - "administratorLogin": { - "reference": { - "keyVault": { - "id": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-<>-az-kv-x-001" - }, - "secretName": "administratorLogin" - } - }, - "administratorLoginPassword": { - "reference": { - "keyVault": { - "id": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-<>-az-kv-x-001" - }, - "secretName": "administratorLoginPassword" - } - }, - "subnetId": { - "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/adp-<>-az-vnet-x-sqlmi/subnets/<>-az-subnet-x-sqlmi" - } - } -} diff --git a/modules/Microsoft.Sql/managedInstances/.test/min/dependencies.bicep b/modules/Microsoft.Sql/managedInstances/.test/min/dependencies.bicep new file mode 100644 index 0000000000..43f7e59e19 --- /dev/null +++ b/modules/Microsoft.Sql/managedInstances/.test/min/dependencies.bicep @@ -0,0 +1,289 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Network Security Group to create.') +param networkSecurityGroupName string + +@description('Required. The name of the Route Table to create.') +param routeTableName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +var sqlMiVnetAddressPrefix = '10.0.0.0/16' +var sqlMiSubnetAddressPrefix = '10.0.0.0/24' +var sqlMiSubnetAddressPrefixString = replace(replace(sqlMiSubnetAddressPrefix, '.', '-'), '/', '-') + +resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2021-08-01' = { + name: networkSecurityGroupName + location: location + properties: { + securityRules: [ + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-sqlmgmt-in-${sqlMiSubnetAddressPrefixString}-v10' + properties: { + description: 'Allow MI provisioning Control Plane Deployment and Authentication Service' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: 'SqlManagement' + destinationAddressPrefix: sqlMiSubnetAddressPrefix + access: 'Allow' + priority: 100 + direction: 'Inbound' + destinationPortRanges: [ + '9000' + '9003' + '1438' + '1440' + '1452' + ] + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-corpsaw-in-${sqlMiSubnetAddressPrefixString}-v10' + properties: { + description: 'Allow MI Supportability' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: 'CorpNetSaw' + destinationAddressPrefix: sqlMiSubnetAddressPrefix + access: 'Allow' + priority: 101 + direction: 'Inbound' + destinationPortRanges: [ + '9000' + '9003' + '1440' + ] + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-corppublic-in-${sqlMiSubnetAddressPrefixString}-v10' + properties: { + description: 'Allow MI Supportability through Corpnet ranges' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: 'CorpNetPublic' + destinationAddressPrefix: sqlMiSubnetAddressPrefix + access: 'Allow' + priority: 102 + direction: 'Inbound' + destinationPortRanges: [ + '9000' + '9003' + ] + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-healthprobe-in-${sqlMiSubnetAddressPrefixString}-v10' + properties: { + description: 'Allow Azure Load Balancer inbound traffic' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: 'AzureLoadBalancer' + destinationAddressPrefix: sqlMiSubnetAddressPrefix + access: 'Allow' + priority: 103 + direction: 'Inbound' + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-internal-in-${sqlMiSubnetAddressPrefixString}-v10' + properties: { + description: 'Allow MI internal inbound traffic' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: sqlMiSubnetAddressPrefix + destinationAddressPrefix: sqlMiSubnetAddressPrefix + access: 'Allow' + priority: 104 + direction: 'Inbound' + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-services-out-${sqlMiSubnetAddressPrefixString}-v10' + properties: { + description: 'Allow MI services outbound traffic over https' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: sqlMiSubnetAddressPrefix + destinationAddressPrefix: 'AzureCloud' + access: 'Allow' + priority: 100 + direction: 'Outbound' + destinationPortRanges: [ + '443' + '12000' + ] + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-internal-out-${sqlMiSubnetAddressPrefixString}-v10' + properties: { + description: 'Allow MI internal outbound traffic' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: sqlMiSubnetAddressPrefix + destinationAddressPrefix: sqlMiSubnetAddressPrefix + access: 'Allow' + priority: 101 + direction: 'Outbound' + } + } + ] + } +} + +resource routeTable 'Microsoft.Network/routeTables@2021-08-01' = { + name: routeTableName + location: location + properties: { + disableBgpRoutePropagation: false + routes: [ + { + name: 'Microsoft.Sql-managedInstances_UseOnly_subnet-${sqlMiSubnetAddressPrefixString}-to-vnetlocal' + properties: { + addressPrefix: sqlMiSubnetAddressPrefix + nextHopType: 'VnetLocal' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-Storage' + properties: { + addressPrefix: 'Storage' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-SqlManagement' + properties: { + addressPrefix: 'SqlManagement' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-AzureMonitor' + properties: { + addressPrefix: 'AzureMonitor' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-CorpNetSaw' + properties: { + addressPrefix: 'CorpNetSaw' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-CorpNetPublic' + properties: { + addressPrefix: 'CorpNetPublic' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-AzureActiveDirectory' + properties: { + addressPrefix: 'AzureActiveDirectory' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-AzureCloud.westeurope' + properties: { + addressPrefix: 'AzureCloud.westeurope' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-AzureCloud.northeurope' + properties: { + addressPrefix: 'AzureCloud.northeurope' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-Storage.westeurope' + properties: { + addressPrefix: 'Storage.westeurope' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-Storage.northeurope' + properties: { + addressPrefix: 'Storage.northeurope' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-EventHub.westeurope' + properties: { + addressPrefix: 'EventHub.westeurope' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + { + name: 'Microsoft.Sql-managedInstances_UseOnly_mi-EventHub.northeurope' + properties: { + addressPrefix: 'EventHub.northeurope' + nextHopType: 'Internet' + hasBgpOverride: false + } + } + ] + } +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2022-01-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + sqlMiVnetAddressPrefix + ] + } + subnets: [ + { + name: 'ManagedInstance' + properties: { + addressPrefix: sqlMiSubnetAddressPrefix + routeTable: { + id: routeTable.id + } + networkSecurityGroup: { + id: networkSecurityGroup.id + } + delegations: [ + { + name: 'managedInstanceDelegation' + properties: { + serviceName: 'Microsoft.Sql/managedInstances' + } + } + ] + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/modules/Microsoft.Sql/managedInstances/.test/min/deploy.test.bicep b/modules/Microsoft.Sql/managedInstances/.test/min/deploy.test.bicep new file mode 100644 index 0000000000..e2cc67d9c3 --- /dev/null +++ b/modules/Microsoft.Sql/managedInstances/.test/min/deploy.test.bicep @@ -0,0 +1,55 @@ +targetScope = 'subscription' + +// ========== // +// Parameters // +// ========== // +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(80) +param resourceGroupName string = 'ms.sql.managedinstances-${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 = 'sqlmimin' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module resourceGroupResources 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-<>-vnet-${serviceShort}' + networkSecurityGroupName: 'dep-<>-nsg-${serviceShort}' + routeTableName: 'dep-<>-rt-${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../deploy.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + name: '<>-${serviceShort}' + administratorLogin: 'adminUserName' + administratorLoginPassword: password + subnetId: resourceGroupResources.outputs.subnetResourceId + } +} diff --git a/modules/Microsoft.Sql/managedInstances/.test/parameters.json b/modules/Microsoft.Sql/managedInstances/.test/parameters.json deleted file mode 100644 index 3537d425c6..0000000000 --- a/modules/Microsoft.Sql/managedInstances/.test/parameters.json +++ /dev/null @@ -1,150 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "name": { - "value": "<>-az-sqlmi-x-001" - }, - "lock": { - "value": "CanNotDelete" - }, - "administratorLogin": { - "reference": { - "keyVault": { - "id": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-<>-az-kv-x-001" - }, - "secretName": "administratorLogin" - } - }, - "administratorLoginPassword": { - "reference": { - "keyVault": { - "id": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-<>-az-kv-x-001" - }, - "secretName": "administratorLoginPassword" - } - }, - "subnetId": { - "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/adp-<>-az-vnet-x-sqlmi/subnets/<>-az-subnet-x-sqlmi" - }, - "skuName": { - "value": "GP_Gen5" - }, - "skuTier": { - "value": "GeneralPurpose" - }, - "storageSizeInGB": { - "value": 32 - }, - "vCores": { - "value": 4 - }, - "licenseType": { - "value": "LicenseIncluded" - }, - "hardwareFamily": { - "value": "Gen5" - }, - "servicePrincipal": { - "value": "SystemAssigned" - }, - "dnsZonePartner": { - "value": "" - }, - "timezoneId": { - "value": "UTC" - }, - "collation": { - "value": "SQL_Latin1_General_CP1_CI_AS" - }, - "proxyOverride": { - "value": "Proxy" - }, - "systemAssignedIdentity": { - "value": true - }, - "userAssignedIdentities": { - "value": { - "/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001": {} - } - }, - "primaryUserAssignedIdentityId": { - "value": "/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001" - }, - "publicDataEndpointEnabled": { - "value": false - }, - "roleAssignments": { - "value": [ - { - "roleDefinitionIdOrName": "Reader", - "principalIds": [ - "<>" - ] - } - ] - }, - "keys": { - "value": [ - { - "name": "adp-<>-az-kv-x-sqlmi_keyEncryptionKeySqlMi_4bf367f64c914d8ba698700fb598ad07", // ID must be updated for new keys - "uri": "https://adp-<>-az-kv-x-sqlmi.vault.azure.net/keys/keyEncryptionKeySqlMi/4bf367f64c914d8ba698700fb598ad07", // ID must be updated for new keys - "serverKeyType": "AzureKeyVault" - } - ] - }, - "encryptionProtectorObj": { - "value": { - "serverKeyName": "adp-<>-az-kv-x-sqlmi_keyEncryptionKeySqlMi_4bf367f64c914d8ba698700fb598ad07", // ID must be updated for new keys - "serverKeyType": "AzureKeyVault" - } - }, - "securityAlertPoliciesObj": { - "value": { - "name": "default", - "state": "Enabled", - "emailAccountAdmins": true - } - }, - "vulnerabilityAssessmentsObj": { - "value": { - "name": "default", - "emailSubscriptionAdmins": true, - "recurringScansIsEnabled": true, - "recurringScansEmails": [ - "test1@contoso.com", - "test2@contoso.com" - ], - "vulnerabilityAssessmentsStorageAccountId": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Storage/storageAccounts/adp<>azsax001" - } - }, - "databases": { - "value": [ - { - "name": "<>-az-sqlmidb-x-001", - "backupShortTermRetentionPolicies": { - "name": "default" - }, - "backupLongTermRetentionPolicies": { - "name": "default" - } - } - ] - }, - "diagnosticLogsRetentionInDays": { - "value": 7 - }, - "diagnosticStorageAccountId": { - "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Storage/storageAccounts/adp<>azsax001" - }, - "diagnosticWorkspaceId": { - "value": "/subscriptions/<>/resourcegroups/validation-rg/providers/microsoft.operationalinsights/workspaces/adp-<>-az-law-x-001" - }, - "diagnosticEventHubAuthorizationRuleId": { - "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.EventHub/namespaces/adp-<>-az-evhns-x-001/AuthorizationRules/RootManageSharedAccessKey" - }, - "diagnosticEventHubName": { - "value": "adp-<>-az-evh-x-001" - } - } -} diff --git a/modules/Microsoft.Sql/managedInstances/deploy.bicep b/modules/Microsoft.Sql/managedInstances/deploy.bicep index 7bf9a767ae..f4acbbb766 100644 --- a/modules/Microsoft.Sql/managedInstances/deploy.bicep +++ b/modules/Microsoft.Sql/managedInstances/deploy.bicep @@ -370,6 +370,9 @@ module managedInstance_encryptionProtector 'encryptionProtector/deploy.bicep' = autoRotationEnabled: contains(encryptionProtectorObj, 'autoRotationEnabled') ? encryptionProtectorObj.autoRotationEnabled : true enableDefaultTelemetry: enableReferencedModulesTelemetry } + dependsOn: [ + managedInstance_keys + ] } module managedInstance_administrator 'administrators/deploy.bicep' = if (!empty(administratorsObj)) { diff --git a/modules/Microsoft.Sql/managedInstances/readme.md b/modules/Microsoft.Sql/managedInstances/readme.md index 01b361840a..cfc96ef54d 100644 --- a/modules/Microsoft.Sql/managedInstances/readme.md +++ b/modules/Microsoft.Sql/managedInstances/readme.md @@ -288,91 +288,20 @@ The following module usage examples are retrieved from the content of the files >**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. -

Example 1: Min

+

Example 1: Common

via Bicep module ```bicep -resource kv1 'Microsoft.KeyVault/vaults@2019-09-01' existing = { - name: 'adp-<>-az-kv-x-001' - scope: resourceGroup('<>','validation-rg') -} - -module managedInstances './Microsoft.Sql/managedInstances/deploy.bicep' = { - name: '${uniqueString(deployment().name)}-ManagedInstances' - params: { - // Required parameters - administratorLogin: kv1.getSecret('administratorLogin') - administratorLoginPassword: kv1.getSecret('administratorLoginPassword') - name: '<>-az-sqlmi-min-001' - subnetId: '/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/adp-<>-az-vnet-x-sqlmi/subnets/<>-az-subnet-x-sqlmi' - } -} -``` - -
-

- -

- -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 - "administratorLogin": { - "reference": { - "keyVault": { - "id": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-<>-az-kv-x-001" - }, - "secretName": "administratorLogin" - } - }, - "administratorLoginPassword": { - "reference": { - "keyVault": { - "id": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-<>-az-kv-x-001" - }, - "secretName": "administratorLoginPassword" - } - }, - "name": { - "value": "<>-az-sqlmi-min-001" - }, - "subnetId": { - "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/adp-<>-az-vnet-x-sqlmi/subnets/<>-az-subnet-x-sqlmi" - } - } -} -``` - -
-

- -

Example 2: Parameters

- -
- -via Bicep module - -```bicep -resource kv1 'Microsoft.KeyVault/vaults@2019-09-01' existing = { - name: 'adp-<>-az-kv-x-001' - scope: resourceGroup('<>','validation-rg') -} - module managedInstances './Microsoft.Sql/managedInstances/deploy.bicep' = { - name: '${uniqueString(deployment().name)}-ManagedInstances' + name: '${uniqueString(deployment().name, location)}-test-sqlmicom' params: { - administratorLogin: kv1.getSecret('administratorLogin') - administratorLoginPassword: kv1.getSecret('administratorLoginPassword') - name: '<>-az-sqlmi-x-001' - subnetId: '/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/adp-<>-az-vnet-x-sqlmi/subnets/<>-az-subnet-x-sqlmi' + administratorLogin: 'adminUserName' + administratorLoginPassword: '' + name: '<>-sqlmicom' + subnetId: '' collation: 'SQL_Latin1_General_CP1_CI_AS' databases: [ { @@ -382,36 +311,36 @@ module managedInstances './Microsoft.Sql/managedInstances/deploy.bicep' = { backupShortTermRetentionPolicies: { name: 'default' } - name: '<>-az-sqlmidb-x-001' + name: '<>-sqlmicom-db-001' } ] - diagnosticEventHubAuthorizationRuleId: '/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.EventHub/namespaces/adp-<>-az-evhns-x-001/AuthorizationRules/RootManageSharedAccessKey' - diagnosticEventHubName: 'adp-<>-az-evh-x-001' + diagnosticEventHubAuthorizationRuleId: '' + diagnosticEventHubName: '' diagnosticLogsRetentionInDays: 7 - diagnosticStorageAccountId: '/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Storage/storageAccounts/adp<>azsax001' - diagnosticWorkspaceId: '/subscriptions/<>/resourcegroups/validation-rg/providers/microsoft.operationalinsights/workspaces/adp-<>-az-law-x-001' + diagnosticStorageAccountId: '' + diagnosticWorkspaceId: '' dnsZonePartner: '' encryptionProtectorObj: { - serverKeyName: 'adp-<>-az-kv-x-sqlmi_keyEncryptionKeySqlMi_4bf367f64c914d8ba698700fb598ad07' + serverKeyName: '' serverKeyType: 'AzureKeyVault' } hardwareFamily: 'Gen5' keys: [ { - name: 'adp-<>-az-kv-x-sqlmi_keyEncryptionKeySqlMi_4bf367f64c914d8ba698700fb598ad07' + name: '' serverKeyType: 'AzureKeyVault' - uri: 'https://adp-<>-az-kv-x-sqlmi.vault.azure.net/keys/keyEncryptionKeySqlMi/4bf367f64c914d8ba698700fb598ad07' + uri: '' } ] licenseType: 'LicenseIncluded' lock: 'CanNotDelete' - primaryUserAssignedIdentityId: '/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001' + primaryUserAssignedIdentityId: '' proxyOverride: 'Proxy' publicDataEndpointEnabled: false roleAssignments: [ { principalIds: [ - '<>' + '' ] roleDefinitionIdOrName: 'Reader' } @@ -428,7 +357,7 @@ module managedInstances './Microsoft.Sql/managedInstances/deploy.bicep' = { systemAssignedIdentity: true timezoneId: 'UTC' userAssignedIdentities: { - '/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001': {} + '': {} } vCores: 4 vulnerabilityAssessmentsObj: { @@ -439,7 +368,7 @@ module managedInstances './Microsoft.Sql/managedInstances/deploy.bicep' = { 'test2@contoso.com' ] recurringScansIsEnabled: true - vulnerabilityAssessmentsStorageAccountId: '/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Storage/storageAccounts/adp<>azsax001' + vulnerabilityAssessmentsStorageAccountId: '' } } } @@ -458,26 +387,16 @@ module managedInstances './Microsoft.Sql/managedInstances/deploy.bicep' = { "contentVersion": "1.0.0.0", "parameters": { "administratorLogin": { - "reference": { - "keyVault": { - "id": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-<>-az-kv-x-001" - }, - "secretName": "administratorLogin" - } + "value": "adminUserName" }, "administratorLoginPassword": { - "reference": { - "keyVault": { - "id": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-<>-az-kv-x-001" - }, - "secretName": "administratorLoginPassword" - } + "value": "" }, "name": { - "value": "<>-az-sqlmi-x-001" + "value": "<>-sqlmicom" }, "subnetId": { - "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/adp-<>-az-vnet-x-sqlmi/subnets/<>-az-subnet-x-sqlmi" + "value": "" }, "collation": { "value": "SQL_Latin1_General_CP1_CI_AS" @@ -491,31 +410,31 @@ module managedInstances './Microsoft.Sql/managedInstances/deploy.bicep' = { "backupShortTermRetentionPolicies": { "name": "default" }, - "name": "<>-az-sqlmidb-x-001" + "name": "<>-sqlmicom-db-001" } ] }, "diagnosticEventHubAuthorizationRuleId": { - "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.EventHub/namespaces/adp-<>-az-evhns-x-001/AuthorizationRules/RootManageSharedAccessKey" + "value": "" }, "diagnosticEventHubName": { - "value": "adp-<>-az-evh-x-001" + "value": "" }, "diagnosticLogsRetentionInDays": { "value": 7 }, "diagnosticStorageAccountId": { - "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Storage/storageAccounts/adp<>azsax001" + "value": "" }, "diagnosticWorkspaceId": { - "value": "/subscriptions/<>/resourcegroups/validation-rg/providers/microsoft.operationalinsights/workspaces/adp-<>-az-law-x-001" + "value": "" }, "dnsZonePartner": { "value": "" }, "encryptionProtectorObj": { "value": { - "serverKeyName": "adp-<>-az-kv-x-sqlmi_keyEncryptionKeySqlMi_4bf367f64c914d8ba698700fb598ad07", + "serverKeyName": "", "serverKeyType": "AzureKeyVault" } }, @@ -525,9 +444,9 @@ module managedInstances './Microsoft.Sql/managedInstances/deploy.bicep' = { "keys": { "value": [ { - "name": "adp-<>-az-kv-x-sqlmi_keyEncryptionKeySqlMi_4bf367f64c914d8ba698700fb598ad07", + "name": "", "serverKeyType": "AzureKeyVault", - "uri": "https://adp-<>-az-kv-x-sqlmi.vault.azure.net/keys/keyEncryptionKeySqlMi/4bf367f64c914d8ba698700fb598ad07" + "uri": "" } ] }, @@ -538,7 +457,7 @@ module managedInstances './Microsoft.Sql/managedInstances/deploy.bicep' = { "value": "CanNotDelete" }, "primaryUserAssignedIdentityId": { - "value": "/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001" + "value": "" }, "proxyOverride": { "value": "Proxy" @@ -550,7 +469,7 @@ module managedInstances './Microsoft.Sql/managedInstances/deploy.bicep' = { "value": [ { "principalIds": [ - "<>" + "" ], "roleDefinitionIdOrName": "Reader" } @@ -583,7 +502,7 @@ module managedInstances './Microsoft.Sql/managedInstances/deploy.bicep' = { }, "userAssignedIdentities": { "value": { - "/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001": {} + "": {} } }, "vCores": { @@ -598,7 +517,7 @@ module managedInstances './Microsoft.Sql/managedInstances/deploy.bicep' = { "test2@contoso.com" ], "recurringScansIsEnabled": true, - "vulnerabilityAssessmentsStorageAccountId": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Storage/storageAccounts/adp<>azsax001" + "vulnerabilityAssessmentsStorageAccountId": "" } } } @@ -607,3 +526,54 @@ module managedInstances './Microsoft.Sql/managedInstances/deploy.bicep' = {

+ +

Example 2: Min

+ +
+ +via Bicep module + +```bicep +module managedInstances './Microsoft.Sql/managedInstances/deploy.bicep' = { + name: '${uniqueString(deployment().name, location)}-test-sqlmimin' + params: { + // Required parameters + administratorLogin: 'adminUserName' + administratorLoginPassword: '' + name: '<>-sqlmimin' + subnetId: '' + } +} +``` + +
+

+ +

+ +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 + "administratorLogin": { + "value": "adminUserName" + }, + "administratorLoginPassword": { + "value": "" + }, + "name": { + "value": "<>-sqlmimin" + }, + "subnetId": { + "value": "" + } + } +} +``` + +
+

diff --git a/utilities/pipelines/resourceRemoval/Initialize-DeploymentRemoval.ps1 b/utilities/pipelines/resourceRemoval/Initialize-DeploymentRemoval.ps1 index 1983185e83..c8e19f36f1 100644 --- a/utilities/pipelines/resourceRemoval/Initialize-DeploymentRemoval.ps1 +++ b/utilities/pipelines/resourceRemoval/Initialize-DeploymentRemoval.ps1 @@ -74,6 +74,7 @@ function Initialize-DeploymentRemoval { 'Microsoft.OperationalInsights/workspaces/linkedServices', 'Microsoft.OperationalInsights/workspaces', 'Microsoft.KeyVault/vaults', + 'Microsoft.Sql/managedInstances', 'Microsoft.Resources/resourceGroups', 'Microsoft.Compute/virtualMachines' )