Azure VPN Gateway Basic Sku.. The poor man’s P2S VPN solution. Or is it?
If you check the notes on the Azure VPN Basic Sku P2S solution:
This table is taken from https://docs.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-about-vpngateways and it shows the limitations of the Basic Sku. The table goes on and on, but I just wanted to show the Basic Sku’s properties. Specifically the P2S options. SSTP only, 128 (simultaneous) connections. More than enough for small businesses. Or home labs. BGP not supported, which means you need to take care of routing tables yourself. A maximum of 10 S2S tunnels, which means you can connect 10 sites to the Virtual Network holding the VPN Gateway deployment. Again, more than enough for small businesses. Or home Labs.
Looking at pricing:
This table is taken from https://azure.microsoft.com/en-us/pricing/details/vpn-gateway/ and it shows pricing in Euros for West Europe. Basic Sku is by far the cheapest solution.
In short, Basic Sku seems like the perfect solution for small businesses and especially for home Labs.
The only thing I don’t like about the Basic Sku is the P2S Client options you get out of the box when you deploy the solution. The out of the box solution and how to get there is not in scope of this post. You can find more info and instructions in some of my other posts:
https://msfreaks.wordpress.com/2015/12/07/building-an-azure-lab-implementing-p2s-point-to-site-vpn/ (Classic, but shows the basic implementation).
So I started some research on how to effectively deploy and manage the VPN client (on Windows 10) when using the Azure VPN Gateway Basic Sku.
For reference, this is the setup for my VPN infrastructure, showing the managed Windows 10 client on which I want to deploy the P2S VPN connection:
First, let’s have a look at why I don’t like the out of the box VPN client options.
You can download your VPN client package in the Point-to-site configuration blade for your VPN Gateway. I specifically say “your” because this package is tailored for this VPN Gateway, and this VPN Gateway only. That is why it takes a little while before your download starts.
The download is a zip file, which once extracted, shows 3 client options:
A “Generic” “Client”, a x64 client package, and a x86 client package. The Generic client simply shows an xml file and the Gateway certificate. Examine the xml file, it will tell you all sort of configuration stuff for the VPN Client:
From this we can get the actual VPN Gateway address, the type, which is SSTP, the routes that are needed, and the authentication method that is needed.
Creating a PKI, and getting the right certificates installed is out of scope of this post.
Let’s check the obvious choice, the x64 client package.
Installing the package in the user context:
Oops. Unsigned, meaning crappy user experience. Ignoring that for now, click “More info” and click “Run anyway”.
Oops. Need elevated administrator access to install this.
Let’s see if it installs machine-wide using an administrator account. Logging on with an administrator and running the same setup again:
So no pesky SmartScreen popup for administrators.
VPN Connection available.
Now logging back in with the normal user, without administrative permissions:
No VPN Connection. So the installation of the VPN Client package is not a machine-wide installer, when using an administrative account. It shows up for the administrator I am logged on with, so it will also not show up for a normal user. Spoiler-alert: even running it as System, using psexec, it will not install machine-wide.
So how to install the connection in the user context, or how to install the connection machine wide, and of course, I want it to be unattended.
Looking around my favorite wiki (google.com) to look for solutions other people have come up with, I found this excellent article which got me started: https://www.risual.com/2018/07/05/manually-configure-azure-point-to-site-on-windows-10/.
I have two issues with this solution though.
First one is a pesky (one-time) certificate warning.
For which a workaround could probably be found. It’s a one-time thing, it has to be registered somewhere right? But the second problem with this solution, and one that prevented me from trying to figure out how to get rid of the first one, is that you need to add routes to tell your machine where to route packets if they are meant to go to the Azure Virtual Network using the VPN Gateway.
A normal user does not have enough rights to do this, and besides, I don’t want them to be static. Like a proper VPN Connection, routes should be added as needed when the connection is established and they need to be removed when the connection is ended or disconnected.
Thank you Risual, close, but no cigar.
So what other options are left? Well, Windows 10 has a native VPN provider (the same one that is used in the article from Risual), and it can be configured using xml VPNv2 profiles.
More information on VPNv2 xml profiles can be found here: https://docs.microsoft.com/en-us/windows/client-management/mdm/vpnv2-csp.
Cool thing about these profiles is that they can be used for deployment using Intune.
Let’s dig into configuring that. I will show you how to capture a VPNv2 xml for deployment in Intune.
First make sure that the Root certificate from the Point-to-site configuration on the VPN Gateway is also a Trusted Root certificate on the machine on which you configure the next steps. Also make sure you have a client certificate that matches that Root certificate in the certificate path. Again, doing so, and configuring those certificates, is outside of the scope of this post.
Those certificates not required to capture the VPN profile which I am about to show you, but they are required if you also want to test the profile before capturing it.
In the Start Menu, type “VPN”.
Click “Add a VPN connection”.
Click “Add a VPN connection”.
Choose “Windows (built-in)” as VPN provider. I entered my Azure VPN Gateway name as the Connection Name. For Server name or address provide the address that you can get from the xml in the “Generic Client” folder. VPN type should be Automatic, because SSTP type is not (yet) supported, Type of sign-in info should be Certificate. I also left the Remember my sign-in info check enabled.
Now click Change adapter options and open the properties for the newly created adapter.
On the Security tab, switch Data encryption to “Require encryption” and then click Properties.
Uncheck Verify the server’s identity (gets rid of the certificate warning which remained in the Risual article).
Click OK three times and test the connection (Remembering that testing only works if you have the Root certificate and a valid user certificate installed on the machine you are using to capture the VPN profile):
Success! At least for the first part. The routes are still not there. And it’s a manual nightmare. Fret not, we will get there. We will use this VPN connection to build our own VPNv2 xml profile.
Time to grab the xml from the profile we just created.
Run the following PowerShell code (after replacing my values with your own values for the variables $Name, $Server, $DnsSuffix, $OutputFile, and $RouteConfig before running it):
$Name = "ITW-01" $Server = "azuregateway-e4850069-xxxx-xxxx-xxxx-ae72007d9e79-585c3b92babd.vpn.azure.com" $DnsSuffix = "it-worxx.local" $OutputFile = "$($env:TEMP)\VPNv2_Profile.xml" $RouteConfig = @("<Route><Address>192.168.2.0</Address><PrefixSize>24</PrefixSize></Route> <Route><Address>10.161.253.0</Address><PrefixSize>24</PrefixSize></Route> <Route><Address>10.162.253.0</Address><PrefixSize>24</PrefixSize></Route> <Route><Address>10.163.253.0</Address><PrefixSize>24</PrefixSize></Route> <Route><Address>10.164.253.0</Address><PrefixSize>24</PrefixSize></Route>") @("<VPNProfile> <ProfileName>$($Name.ToLower())profile</ProfileName> <!-- the dns suffix to use for the vpn adapter --> <DnsSuffix>$($DnsSuffix)</DnsSuffix> <NativeProfile> <!-- the azure vpn gateway address goes here --> <Servers>$Server</Servers> <!-- for azure vpn gateway basic sku this must be Automatic --> <NativeProtocolType>Automatic</NativeProtocolType> <Authentication> <!-- this must be eap and a valid eap configuration must be supplied --> <UserMethod>Eap</UserMethod> <Eap> <Configuration> <!-- sabm eap configuration taken from template profile --> $((Get-VpnConnection -Name $Name).EapConfigXmlStream.InnerXml) </Configuration> </Eap> </Authentication> <!-- activate splittunnel configuration --> <RoutingPolicyType>SplitTunnel</RoutingPolicyType> <!-- disable class based default route --> <DisableClassBasedDefaultRoute>true</DisableClassBasedDefaultRoute> </NativeProfile> <RememberCredentials>true</RememberCredentials> <!-- add route config for this connection --> $RouteConfig </VPNProfile>") | Out-File -FilePath $OutputFile
The result will be an xml file in your output destination, which, you guessed right, is the VPNv2 xml profile. Mine looks like this when I run the script:
<VPNProfile> <ProfileName>it-worxxprofile</ProfileName> <!-- the dns suffix to use for the vpn adapter --> <DnsSuffix>it-worxx.local</DnsSuffix> <NativeProfile> <!-- the azure vpn gateway address goes here --> <Servers>azuregateway-e4850069-xxxx-xxxx-xxxx-ae72007d9e79-585c3b92babd.vpn.azure.com</Servers> <!-- for azurre vpn gateway basic sku this must be Automatic --> <NativeProtocolType>Automatic</NativeProtocolType> <Authentication> <!-- this must be eap and a valid eap configuration must be supplied --> <UserMethod>Eap</UserMethod> <Eap> <Configuration> <!-- sabm eap configuration taken from template profile --> <EapHostConfig xmlns="http://www.microsoft.com/provisioning/EapHostConfig"><EapMethod><Type xmlns="http://www.microsoft.com/provisioning/EapCommon">13</Type><VendorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorId><VendorType xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorType><AuthorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</AuthorId></EapMethod><Config xmlns="http://www.microsoft.com/provisioning/EapHostConfig"><Eap xmlns="http://www.microsoft.com/provisioning/BaseEapConnectionPropertiesV1"><Type>13</Type><EapType xmlns="http://www.microsoft.com/provisioning/EapTlsConnectionPropertiesV1"><CredentialsSource><CertificateStore><SimpleCertSelection>true</SimpleCertSelection></CertificateStore></CredentialsSource><ServerValidation><DisableUserPromptForServerValidation>false</DisableUserPromptForServerValidation><ServerNames></ServerNames></ServerValidation><DifferentUsername>false</DifferentUsername><PerformServerValidation xmlns="http://www.microsoft.com/provisioning/EapTlsConnectionPropertiesV2">false</PerformServerValidation><AcceptServerName xmlns="http://www.microsoft.com/provisioning/EapTlsConnectionPropertiesV2">false</AcceptServerName><TLSExtensions xmlns="http://www.microsoft.com/provisioning/EapTlsConnectionPropertiesV2"><FilteringInfo xmlns="http://www.microsoft.com/provisioning/EapTlsConnectionPropertiesV3"><CAHashList><IssuerHash>8c ff ff ff ff b3 c9 20 3f c1 b1 da 3f 02 77 b5 93 fd 3b 3e </IssuerHash></CAHashList></FilteringInfo></TLSExtensions></EapType></Eap></Config></EapHostConfig> </Configuration> </Eap> </Authentication> <!-- activate splittunnel configuration --> <RoutingPolicyType>SplitTunnel</RoutingPolicyType> <!-- disable class based default route --> <DisableClassBasedDefaultRoute>true</DisableClassBasedDefaultRoute> </NativeProfile> <RememberCredentials>true</RememberCredentials> <!-- add route config for this connection --> <Route><Address>192.168.2.0</Address><PrefixSize>24</PrefixSize></Route> <Route><Address>10.161.253.0</Address><PrefixSize>24</PrefixSize></Route> <Route><Address>10.162.253.0</Address><PrefixSize>24</PrefixSize></Route> <Route><Address>10.163.253.0</Address><PrefixSize>24</PrefixSize></Route> <Route><Address>10.164.253.0</Address><PrefixSize>24</PrefixSize></Route> </VPNProfile>
And this is the profile data we can use to publish the profile using Intune.
In Intune, create a new Configuration Profile.
Give it a name, select Windows 10 and later for Platform, and most importantly, select Custom Profile Type.
In the Custom OMA-URI settings tab click Add.
Name and Description really don’t matter. What’s important here is the OMA-URI. This should be like “./user/vendor/MSFT/VPNv2/<profile name>/ProfileXML” where “<profile name>” will be the name for the VPN connection once it’s deployed and visible in Windows 10. In my case I entered “./user/vendor/MSFT/VPNv2/IT-WorXX/ProfileXML” as the OMA-URI. Also note here that this profile name setting does not have to match the profile name that you used to capture the VPNv2 profile.
The Data type must be string, and in the Value field you paste the captured profile xml.
When you’re done don’t forget to assign the profile. I chose to assign it to All users.
Time to test the setup.
When I log on to a managed device with a user that has the VPN profile assigned, it shows up in the available connections.
In the above screenshot you can see the initial IP Config output, and the IP Config output with the “IT-WorXX” VPN connection in a connected state.
The initial IPv4 Route Table, which clearly shows there’re no routes to the address spaces in Azure, and no routes to my on-premises networks.
And after connecting the “IT-WorXX” VPN Connection, the IPv4 Routing Table show routes to the Azure address spaces, and the on-premises network.
There’s one more “gotcha” with this setup.
I have configured custom DNS servers on the Azure Virtual Network. What happens here is when I connect the “IT-WorXX” VPN profile, I automatically receive these DNS servers on the VPN client connection:
If for some reason your configuration prevents you from entering custom DNS servers your client will receive no DNS server settings when it is connected.
You can solve this issue by modifying the XML file for the VPNv2 profile between the DnsSuffix and NativeProfile tags:
<VPNProfile> <ProfileName>it-worxxprofile</ProfileName> <!-- the dns suffix to use for the vpn adapter --> <DnsSuffix>it-worxx.local</DnsSuffix> <DomainNameInformation> <DomainName>.it-worxx.local</DomainName> <DnsServers>10.161.253.4,192.168.2.4</DnsServers> </DomainNameInformation> <NativeProfile>
And that’s it. A fully managed VPNv2 profile deployment using Intune, which allows you to connect to an Azure VPN Gateway Basic Sku P2S configuration.
Until next time,