动态更新Azure S2S VPN网关IP地址

在家庭实验室或企业环境中,经常需要建立一个安全的站点到站点(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地址

需要一个方法来识别当前的公网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地址

最后一步是使用新的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地址始终自动刷新其值。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485