在家庭实验室或企业环境中,经常需要建立一个安全的站点到站点(S2S) VPN连接,以连接Azure资源和本地网络。然而,建立此类连接需要一些通常在家庭实验室中不可用的条件。例如,需要一个Azure订阅、一个兼容的VPN设备,以及一个公网静态IP地址,且该IP地址不能位于NAT之后。对于家庭用户来说,拥有VPN设备和静态IP地址的要求似乎有些过高。幸运的是,可以通过设置一个RRAS(路由和远程访问服务)服务器来实现一个便宜且简单的替代方案。本文的目的是介绍如何动态更新S2S VPN连接的静态IP要求,而不是介绍如何建立S2S连接或RRAS服务器。
当需要通过原生.NET代码管理虚拟机、虚拟网络、Web或移动应用、存储帐户时,.NET的管理库就会发挥作用。Azure有两种不同的部署、创建和管理资源的模型:经典模型和资源管理器模型。本文将专注于资源管理器模型,因为经典模型正在逐渐被淘汰。将使用Microsoft.Azure.Management.Network命名空间中的管理库。
首先,需要在AzureAD中注册一个新的应用程序。由于讨论的是控制台应用程序,因此它必须是一个本地应用程序。重定向URI并不重要,但至少填写一些有效且有意义的内容。然后,为应用程序授予Windows Azure服务管理API权限,并创建一个密钥,稍后将在请求应用程序的认证令牌时使用它。
为了能够使用资源管理器模型(ARM),可以通过使用公开的REST API端点,或者直接使用Microsoft提供的.NET包装器。因此,在新的控制台应用程序中添加以下NuGet包:
Microsoft.Azure.Management.ResourceManager
Microsoft.Azure.Management.Network
Microsoft.IdentityModel.Clients.ActiveDirectory
这些足以开始获取认证令牌并使用ARM及其网络资源对应项。然后,需要开始配置应用程序。打开app.config文件,并在appsettings块下添加以下条目:
在app.config文件中,需要添加一些配置信息,以便应用程序可以正确地连接到Azure服务。以下是一些关键的配置项:
<add key="login" value="https://login.windows.net/{0}" />
<add key="aadInstance" value="https://login.microsoftonline.com/{0}" />
<add key="tenantId" value="YOUR AZURE AD TENANT ID" />
<add key="apiEndpoint" value="https://management.azure.com/" />
<add key="clientId" value="THE APP-ID YOUR REGISTERED IN AZURE AD" />
<add key="clientSecretKeyPreviewPortal" value="THE APP SECRET KEY" />
<add key="redirectUri" value="http://iprefresh" />
<add key="subscriptionId" value="YOUR SUBSCRIPTION ID" />
<add key="resourceGroupName" value="rgHybridDevelopmentLab" />
<add key="localNetworkGatewayName" value="localgw-hyde-01" />
为了与ARM API进行通信,需要一个访问令牌。以下是一个获取访问令牌的方法:
private static async Task<AuthenticationResult> GetAccessTokenAsync()
{
var authContextUrl = String.Format("https://login.windows.net/{0}", tenantId);
var cc = new ClientCredential(clientId, clientSecretKeyPreviewPortal);
var context = new AuthenticationContext(authContextUrl);
var token = await context.AcquireTokenAsync(apiEndPoint, cc);
if (token == null)
{
throw new InvalidOperationException("Could not get the Access Token, please check the clientId and clientSecretKey values.");
}
return token;
}
需要一个方法来识别当前的公网IP地址。这可以通过调用各种动态DNS服务的特殊端点来实现:
private static string GetCurrentIPAddress()
{
string ipAddress = String.Empty;
try
{
string url = "http://checkip.dyndns.org";
using (var req = System.Net.WebRequest.Create(url))
using (var resp = req.GetResponse())
using (var sr = new System.IO.StreamReader(resp.GetResponseStream()))
{
string response = sr.ReadToEnd().Trim();
string[] a = response.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
ipAddress = a[1].Substring(1).Trim('<');
}
}
catch (Exception checkIpException)
{
ipAddress = checkIpException.Message;
}
return ipAddress;
}
最后一步是使用新的IP地址更新本地网络网关:
private static async Task SetCurrentIPAddress(IPAddress ipaddr)
{
if (ipaddr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
try
{
Console.WriteLine("Getting Local Network Gateway...");
var token = await GetAccessTokenAsync();
var credentials = new TokenCredentials(token.AccessToken);
var vnetMgmtClient = new NetworkManagementClient(credentials)
{
SubscriptionId = subscriptionId
};
var localGwOperations = vnetMgmtClient.LocalNetworkGateways;
var localGws = await LocalNetworkGatewaysOperationsExtensions.ListAsync(localGwOperations, resourceGroupName);
var localGw = localGws.FirstOrDefault(lgw => lgw.Name == localNetworkGatewayName);
string ipAddress = ipaddr.ToString();
if (localGw != null && localGw.GatewayIpAddress != ipAddress)
{
localGw.GatewayIpAddress = ipAddress;
var updatedLocalGw = await LocalNetworkGatewaysOperationsExtensions.CreateOrUpdateAsync(localGwOperations, resourceGroupName, localGw.Name, localGw);
Console.WriteLine($"Updated Local Network Gateway. New IP Address: {ipAddress}");
}
else
{
Console.WriteLine("No changes applied to Local Network Gateway IP, all in sync.");
}
}
catch (Exception setIpAddressException)
{
Console.WriteLine(setIpAddressException.Message);
Console.WriteLine("Failed to update Local Network Gateway...");
}
}
}
如果已经阅读到这里,假设已经设置了一个RRAS服务器,并且已经与Azure中的虚拟网络建立了S2S连接。创建一个计划任务,最好是在RRAS服务器上,定期(选择了5分钟间隔)获取新的IP并更新本地网络网关,以保持VPN始终在线。然后访问Azure门户中的连接资源,并注意到连接状态始终为已连接,本地网络网关IP地址始终自动刷新其值。