mirror of
https://github.com/Microsoft/sql-server-samples.git
synced 2025-12-08 14:58:54 +00:00
Merge pull request #432 from srdan-bozovic-msft/master
Add: attach vpn gateway sample
This commit is contained in:
@@ -0,0 +1 @@
|
||||
#placeholder
|
||||
@@ -0,0 +1,84 @@
|
||||
# Attaches VPN gateway to Managed Instance virtual network
|
||||
|
||||
### Contents
|
||||
|
||||
[About this sample](#about-this-sample)<br/>
|
||||
[Before you begin](#before-you-begin)<br/>
|
||||
[Run this sample](#run-this-sample)<br/>
|
||||
[Sample details](#sample-details)<br/>
|
||||
[Disclaimers](#disclaimers)<br/>
|
||||
[Related links](#related-links)<br/>
|
||||
|
||||
|
||||
<a name=about-this-sample></a>
|
||||
|
||||
## About this sample
|
||||
|
||||
- **Applies to:** Azure SQL Database
|
||||
- **Key features:** Managed Instance
|
||||
- **Workload:** n/a
|
||||
- **Programming Language:** PowerShell
|
||||
- **Authors:** Srdan Bozovic
|
||||
- **Update history:** n/a
|
||||
|
||||
<a name=before-you-begin></a>
|
||||
|
||||
## Before you begin
|
||||
|
||||
To run this sample, you need the following prerequisites.
|
||||
|
||||
**Software prerequisites:**
|
||||
|
||||
1. PowerShell 5.1
|
||||
2. Azure PowerShell 5.4.2 or higher
|
||||
|
||||
**Azure prerequisites:**
|
||||
|
||||
1. Permission to manage Azure virtual network
|
||||
|
||||
<a name=run-this-sample></a>
|
||||
|
||||
## Run this sample
|
||||
|
||||
Run the script below from Windows PowerShell
|
||||
|
||||
```powershell
|
||||
|
||||
$scriptUrlBase = 'https://raw.githubusercontent.com/Microsoft/sql-server-samples/master/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway'
|
||||
|
||||
$parameters = @{
|
||||
subscriptionId = '<subscriptionId>'
|
||||
resourceGroupName = '<resourceGroupName>'
|
||||
virtualNetworkName = '<virtualNetworkName>'
|
||||
certificateNamePrefix = '<certificateNamePrefix>'
|
||||
}
|
||||
|
||||
Invoke-Command -ScriptBlock ([Scriptblock]::Create((iwr ($scriptUrlBase+'/attachVPNGateway.ps1?t='+ [DateTime]::Now.Ticks)).Content)) -ArgumentList $parameters, $scriptUrlBase
|
||||
|
||||
```
|
||||
|
||||
<a name=sample-details></a>
|
||||
|
||||
## Sample details
|
||||
|
||||
This sample shows how to attach VPN Gateway to Managed Instance virtual network using PowerShell
|
||||
|
||||
This is done in three steps:
|
||||
- Create and install certificates on client machine
|
||||
- Calculate future VPN Gateway subnet IP range
|
||||
- Deploy ARM template that will attach VPN Gateway to subnet
|
||||
|
||||
<a name=disclaimers></a>
|
||||
|
||||
## Disclaimers
|
||||
The scripts and this guide are copyright Microsoft Corporations and are provided as samples. They are not part of any Azure service and are not covered by any SLA or other Azure-related agreements. They are provided as-is with no warranties express or implied. Microsoft takes no responsibility for the use of the scripts or the accuracy of this document. Familiarize yourself with the scripts before using them.
|
||||
|
||||
<a name=related-links></a>
|
||||
|
||||
## Related Links
|
||||
<!-- Links to more articles. Remember to delete "en-us" from the link path. -->
|
||||
|
||||
For more information, see these articles:
|
||||
|
||||
- [What is a Managed Instance (preview)?](https://docs.microsoft.com/azure/sql-database/sql-database-managed-instance)
|
||||
- [Configure a VNet for Azure SQL Database Managed Instance](https://docs.microsoft.com/azure/sql-database/sql-database-managed-instance-vnet-configuration)
|
||||
@@ -0,0 +1,202 @@
|
||||
$parameters = $args[0]
|
||||
|
||||
$subscriptionId = $parameters['subscriptionId']
|
||||
$resourceGroupName = $parameters['resourceGroupName']
|
||||
$virtualNetworkName = $parameters['virtualNetworkName']
|
||||
$certificateNamePrefix = $parameters['certificateNamePrefix']
|
||||
$force = $parameters['force']
|
||||
|
||||
$scriptUrlBase = $args[1]
|
||||
|
||||
function Ensure-Login ()
|
||||
{
|
||||
$context = Get-AzureRmContext
|
||||
If($context.Subscription -eq $null)
|
||||
{
|
||||
Write-Host "Loging in ..."
|
||||
If((Login-AzureRmAccount -ErrorAction SilentlyContinue -ErrorVariable Errors) -eq $null)
|
||||
{
|
||||
Write-Host ("Login failed: {0}" -f $Errors[0].Exception.Message) -ForegroundColor Red
|
||||
Break
|
||||
}
|
||||
}
|
||||
Write-Host "User logedin." -ForegroundColor Green
|
||||
}
|
||||
|
||||
function Select-SubscriptionId {
|
||||
param (
|
||||
$subscriptionId
|
||||
)
|
||||
Write-Host "Selecting subscription '$subscriptionId'."
|
||||
$context = Get-AzureRmContext
|
||||
If($context.Subscription.Id -ne $subscriptionId)
|
||||
{
|
||||
Try
|
||||
{
|
||||
Select-AzureRmSubscription -SubscriptionId $subscriptionId -ErrorAction Stop | Out-null
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Write-Host "Subscription selection failed: $_" -ForegroundColor Red
|
||||
Break
|
||||
}
|
||||
}
|
||||
Write-Host "Subscription selected." -ForegroundColor Green
|
||||
}
|
||||
|
||||
function Load-VirtualNetwork {
|
||||
param (
|
||||
$resourceGroupName,
|
||||
$virtualNetworkName
|
||||
)
|
||||
Write-Host("Loading virtual network '{0}' in resource group '{1}'." -f $virtualNetworkName, $resourceGroupName)
|
||||
$virtualNetwork = Get-AzureRmVirtualNetwork -ResourceGroupName $resourceGroupName -Name $virtualNetworkName -ErrorAction SilentlyContinue
|
||||
If($virtualNetwork.Id -ne $null)
|
||||
{
|
||||
Write-Host "Virtual network loaded." -ForegroundColor Green
|
||||
return $virtualNetwork
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "Virtual network not found." -ForegroundColor Red
|
||||
Break
|
||||
}
|
||||
}
|
||||
|
||||
function Load-ResourceGroup {
|
||||
param (
|
||||
$resourceGroupName
|
||||
)
|
||||
Write-Host("Loading resource group '{0}'." -f $resourceGroupName)
|
||||
$resourceGroup = Get-AzureRmResourceGroup -Name $resourceGroupName
|
||||
If($resourceGroup.ResourceId -ne $null)
|
||||
{
|
||||
Write-Host "Resource group loaded." -ForegroundColor Green
|
||||
return $resourceGroup
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "Resource group not found." -ForegroundColor Red
|
||||
Break
|
||||
}
|
||||
}
|
||||
|
||||
function Set-VirtualNetwork
|
||||
{
|
||||
param($virtualNetwork)
|
||||
|
||||
Write-Host "Applying changes to the virtual network."
|
||||
Try
|
||||
{
|
||||
Set-AzureRmVirtualNetwork -VirtualNetwork $virtualNetwork -ErrorAction Stop | Out-Null
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Write-Host "Failed: $_" -ForegroundColor Red
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function ConvertCidrToUint32Array
|
||||
{
|
||||
param($cidrRange)
|
||||
$cidrRangeParts = $cidrRange.Split(@(".","/"))
|
||||
$ipnum = ([Convert]::ToUInt32($cidrRangeParts[0]) -shl 24) -bor `
|
||||
([Convert]::ToUInt32($cidrRangeParts[1]) -shl 16) -bor `
|
||||
([Convert]::ToUInt32($cidrRangeParts[2]) -shl 8) -bor `
|
||||
[Convert]::ToUInt32($cidrRangeParts[3])
|
||||
|
||||
$maskbits = [System.Convert]::ToInt32($cidrRangeParts[4])
|
||||
$mask = 0xffffffff
|
||||
$mask = $mask -shl (32 -$maskbits)
|
||||
$ipstart = $ipnum -band $mask
|
||||
$ipend = $ipnum -bor ($mask -bxor 0xffffffff)
|
||||
return @($ipstart, $ipend)
|
||||
}
|
||||
|
||||
function ConvertUInt32ToIPAddress
|
||||
{
|
||||
param($uint32IP)
|
||||
$v1 = $uint32IP -band 0xff
|
||||
$v2 = ($uint32IP -shr 8) -band 0xff
|
||||
$v3 = ($uint32IP -shr 16) -band 0xff
|
||||
$v4 = ($uint32IP -shr 24)
|
||||
return "$v4.$v3.$v2.$v1"
|
||||
}
|
||||
|
||||
function CalculateNextAddressPrefix
|
||||
{
|
||||
param($virtualNetwork, $prefixLength)
|
||||
Write-Host "Calculating address prefix."
|
||||
$startIPAddress = 0
|
||||
ForEach($addressPrefix in $virtualNetwork.AddressSpace.AddressPrefixes)
|
||||
{
|
||||
$endIPAddress = (ConvertCidrToUint32Array $addressPrefix)[1]
|
||||
If($endIPAddress -gt $startIPAddress)
|
||||
{
|
||||
$startIPAddress = $endIPAddress
|
||||
}
|
||||
}
|
||||
$startIPAddress += 1
|
||||
return (ConvertUInt32ToIPAddress $startIPAddress) + "/" + $prefixLength
|
||||
}
|
||||
|
||||
function CalculateVpnClientAddressPoolPrefix
|
||||
{
|
||||
param($gatewaySubnetPrefix)
|
||||
Write-Host "Calculating VPN client address pool prefix."
|
||||
If($gatewaySubnetPrefix.StartsWith("10."))
|
||||
{
|
||||
return "192.168.0.0/24"
|
||||
}
|
||||
else
|
||||
{
|
||||
return "172.16.0.0/24"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Ensure-Login
|
||||
Select-SubscriptionId -subscriptionId $subscriptionId
|
||||
|
||||
$virtualNetwork = Load-VirtualNetwork -resourceGroupName $resourceGroupName -virtualNetworkName $virtualNetworkName
|
||||
|
||||
$resourceGroup = Get-AzureRmResourceGroup -Name $resourceGroupName
|
||||
|
||||
$certificate = New-SelfSignedCertificate -Type Custom -KeySpec Signature `
|
||||
-Subject ("CN=$certificateNamePrefix"+"P2SRoot") -KeyExportPolicy Exportable `
|
||||
-HashAlgorithm sha256 -KeyLength 2048 `
|
||||
-CertStoreLocation "Cert:\CurrentUser\My" -KeyUsageProperty Sign -KeyUsage CertSign
|
||||
|
||||
$certificateThumbprint = $certificate.Thumbprint
|
||||
|
||||
New-SelfSignedCertificate -Type Custom -DnsName ($certificateNamePrefix+"P2SChild") -KeySpec Signature `
|
||||
-Subject ("CN=$certificateNamePrefix"+"P2SChild") -KeyExportPolicy Exportable `
|
||||
-HashAlgorithm sha256 -KeyLength 2048 `
|
||||
-CertStoreLocation "Cert:\CurrentUser\My" `
|
||||
-Signer $certificate -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.2") | Out-null
|
||||
|
||||
$publicRootCertData = [Convert]::ToBase64String((Get-Item cert:\currentuser\my\$certificateThumbprint).RawData)
|
||||
|
||||
$gatewaySubnetPrefix = CalculateNextAddressPrefix $virtualNetwork 28
|
||||
|
||||
$vpnClientAddressPoolPrefix = CalculateVpnClientAddressPoolPrefix $gatewaySubnetPrefix
|
||||
|
||||
$virtualNetwork.AddressSpace.AddressPrefixes.Add($gatewaySubnetPrefix)
|
||||
Add-AzureRmVirtualNetworkSubnetConfig -Name GatewaySubnet -VirtualNetwork $virtualNetwork -AddressPrefix $gatewaySubnetPrefix | Out-Null
|
||||
|
||||
Set-VirtualNetwork $virtualNetwork
|
||||
|
||||
Write-Host
|
||||
|
||||
# Start the deployment
|
||||
Write-Host "Starting deployment..."
|
||||
|
||||
$templateParameters = @{
|
||||
virtualNetworkName = $virtualNetworkName
|
||||
gatewaySubnetPrefix = $gatewaySubnetPrefix
|
||||
vpnClientAddressPoolPrefix = $vpnClientAddressPoolPrefix
|
||||
publicRootCertData = $publicRootCertData
|
||||
}
|
||||
|
||||
New-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateUri ($scriptUrlBase+'/azuredeploy.json?t='+ [DateTime]::Now.Ticks) -TemplateParameterObject $templateParameters
|
||||
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.1",
|
||||
"parameters": {
|
||||
"location": {
|
||||
"type": "string",
|
||||
"defaultValue": "[resourceGroup().location]",
|
||||
"metadata": {
|
||||
"description": "Enter location. If you leave this field blank resource group location would be used."
|
||||
}
|
||||
},
|
||||
"virtualNetworkName": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Enter virtual network name. If you leave this field blank name will be created by the template."
|
||||
}
|
||||
},
|
||||
"gatewaySubnetPrefix": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "The prefix for the GatewaySubnet where the VirtualNetworkGateway will be deployed. This must be at least /29."
|
||||
}
|
||||
},
|
||||
"vpnClientAddressPoolPrefix": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "The IP address range from which VPN clients will receive an IP address when connected. Range specified must not overlap with on-premise network."
|
||||
}
|
||||
},
|
||||
"publicRootCertData": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Client root certificate data used to authenticate VPN clients."
|
||||
}
|
||||
}
|
||||
},
|
||||
"variables": {
|
||||
"gatewayPublicIpAddressName": "[concat('GatewayIP-', uniqueString(resourceGroup().id))]",
|
||||
"gatewayName": "[concat('Gateway-', uniqueString(resourceGroup().id))]",
|
||||
"gatewaySku": "Basic",
|
||||
"gatewaySubnetName": "GatewaySubnet",
|
||||
"clientRootCertName": "RootCert"
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"apiVersion": "2017-10-01",
|
||||
"type": "Microsoft.Network/publicIPAddresses",
|
||||
"name": "[variables('gatewayPublicIpAddressName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"properties": {
|
||||
"publicIPAllocationMethod": "Dynamic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"apiVersion": "2017-10-01",
|
||||
"type": "Microsoft.Network/virtualNetworkGateways",
|
||||
"name": "[variables('gatewayName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('gatewayPublicIpAddressName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"ipConfigurations": [
|
||||
{
|
||||
"properties": {
|
||||
"privateIPAllocationMethod": "Dynamic",
|
||||
"subnet": {
|
||||
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), variables('gatewaySubnetName'))]"
|
||||
},
|
||||
"publicIPAddress": {
|
||||
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('gatewayPublicIpAddressName'))]"
|
||||
}
|
||||
},
|
||||
"name": "vnetGatewayConfig"
|
||||
}
|
||||
],
|
||||
"sku": {
|
||||
"name": "[variables('gatewaySku')]",
|
||||
"tier": "[variables('gatewaySku')]"
|
||||
},
|
||||
"gatewayType": "Vpn",
|
||||
"vpnType": "RouteBased",
|
||||
"enableBgp": "false",
|
||||
"vpnClientConfiguration": {
|
||||
"vpnClientAddressPool": {
|
||||
"addressPrefixes": [
|
||||
"[parameters('vpnClientAddressPoolPrefix')]"
|
||||
]
|
||||
},
|
||||
"vpnClientRootCertificates": [
|
||||
{
|
||||
"name": "[variables('clientRootCertName')]",
|
||||
"properties": {
|
||||
"PublicCertData": "[parameters('publicRootCertData')]"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user