Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This section documents how to create an Azure Workbook that shows relevant data of User VPN clients connected to Azure Virtual WAN.
To complete the steps in this article, you need to have a Virtual WAN, a virtual hub, and a User VPN Gateway. To create these resources, follow the steps in this article: Create Virtual WAN, virtual hub, and a gateway
To configure the above architecture, we'll use the following P2S VPN logs and PowerShell command.
AzureDiagnostics: These logs are received by creating a diagnostic setting for the User VPN Gateway and enabling the following logs: GatewayDiagnosticLog, IKEDiagnosticLog, P2SDiagnosticLog, and AllMetrics.
Get-AzP2sVpnGatewayDetailedConnectionHealth: This is a PowerShell command (running in a function app) to get active sessions details. This command only supports storing data in a storage account based on a SAS Key, and it provides additional details about active P2S VPN connections.
- Create Azure storage account.
- Create container and upload a blob to the container
- Your blob should be an empty text file with .json extension
- When uploading the blob, give your Account Key the following permissions: Read, Add, Create, and Write.
- Make sure to copy down the Blob SAS token and Blob SAS URL to a secure location.
Create an Azure function app and select PowerShell Core as your runtime stack
Assign a system assigned managed identity to the function app
Create an application setting with the following 7 entries by inputting the Name and Value and then select OK after each value.
Name Value "resourcegroup" your resource group "sasuri" @Microsoft.KeyVault(SecretUri=https://\<keyvaultname>.vault.azure.cn/secrets/sasuri/<version>)
--> update accordingly after keyvault is created in next section."subscription" your subscription ID "tenantname" your tenant ID "vpngw" This name is something like <guid>-chinaeast2-ps2-gw. You can get this from the vWAN HUB User VPN settings. Select Code + Test in the left panel, and type the following code in the run.ps1 file. Select Save.
# Input bindings are passed in via param block. param($Timer) # Get the current universal time in the default string format. $currentUTCtime = (Get-Date).ToUniversalTime() # The 'IsPastDue' property is "true" when the current function invocation is later than scheduled. if($Timer.IsPastDue){ Write-Host "PowerShell timer is running late!" } ## Write an information log with current time. Write-Host "PowerShell timer trigger function ran! TIME:$currentUTCtime" $tenantname = $env:appsetting_tenantname $subscription = $env:appsetting_subscription $resourceGroup = $env:appsetting_resourcegroup $vpngw = $env:appsetting_vpngw $sasuri = $env:appsetting_sasuri Write-Host "Connecting to Managed Identity..." connect-azaccount -tenant $tenantname -identity -subscription $subscription Write-Host "Executing File Update..." Get-AzP2sVpnGatewayDetailedConnectionHealth -name $vpngw -ResourceGroupName $resourceGroup -OutputBlobSasUrl $sasuri Write-Host "Function Execution Completed!"
Navigate back to the Function App page and select on App Service Editor in the left panel under Development Tools. Then, select Go -->.
Go to requirements.psd1 and uncomment the line beginning with 'Az'... as shown.
For the get-AzP2sVpnGatewayDetailedConnectionHealth command to succeed, you need to have the right permissions to the information. Navigate to your resource group and choose "Access Control (IAM)" in the left panel. This corresponds to identity and access management. Assign the FunctionApp read access over the resource group.
Create Azure Key Vault.
- For Permission model, select Vault access policy.
- Leave the options under Resource access as disabled.
- Under Access policies, select + Create.
- Select Next to go to the Principal tab. Type the name of your function app and select it.
- Select Next twice to get to the fourth tab: Review + create and select Create at the bottom.
- You should now see the newly created access policy under the Access policies section. Modifying the default values under the Networking tab is optional, so select Review + create in the bottom left corner.
Go to Secrets under Objects under the left panel of the key vault resource. Select + Generate/Import and add secret as follows:
- Name: sasuri
- value: <SASURI>
- Enabled: Yes
Go back to the Configuration tab for the Function App and modify the following entry. The value comes from the Secret Identifier field that appears after clicking on the secret:
- Name: "sasuri"
- Value:
@Microsoft.KeyVault(SecretUri=https://\<keyvaultname>.vault.azure.cn/secrets/sasuri/<version>)
The Azure workbook is now ready to be created. We'll use a mix of built-in functionality and the added session details from our function app solution.
Navigate to your Virtual WAN resource and select on Insights under Monitor in the left panel. Select on Workbooks and then select + New.
Add the following query into the workbook. Replace "SASURI" with your sas uri.
let P2Svpnconnections = (externaldata (resource:string, UserNameVpnConnectionHealths: dynamic) [ @"SASURI" ] with(format="multijson")); P2Svpnconnections | mv-expand UserNameVpnConnectionHealths | extend Username = parse_json(UserNameVpnConnectionHealths).UserName | extend VpnConnectionHealths = parse_json(parse_json(UserNameVpnConnectionHealths).VpnConnectionHealths) | mv-expand VpnConnectionHealths | extend VpnConnectionId = parse_json(VpnConnectionHealths).VpnConnectionId, VpnConnectionDuration = parse_json(VpnConnectionHealths).VpnConnectionDuration, VpnConnectionTime = parse_json(VpnConnectionHealths).VpnConnectionTime, PublicIpAddress = parse_json(VpnConnectionHealths).PublicIpAddress, PrivateIpAddress = parse_json(VpnConnectionHealths).PrivateIpAddress, MaxBandwidth = parse_json(VpnConnectionHealths).MaxBandwidth, EgressPacketsTransferred = parse_json(VpnConnectionHealths).EgressPacketsTransferred, EgressBytesTransferred = parse_json(VpnConnectionHealths).EgressBytesTransferred, IngressPacketsTransferred = parse_json(VpnConnectionHealths).IngressPacketsTransferred, IngressBytesTransferred = parse_json(VpnConnectionHealths).IngressBytesTransferred, MaxPacketsPerSecond = parse_json(VpnConnectionHealths).MaxPacketsPerSecond | extend PubIp = tostring(split(PublicIpAddress, ":").[0]) | project Username, VpnConnectionId, VpnConnectionDuration, VpnConnectionTime, PubIp, PublicIpAddress, PrivateIpAddress, MaxBandwidth, EgressPacketsTransferred, EgressBytesTransferred, IngressPacketsTransferred, IngressBytesTransferred, MaxPacketsPerSecond;
To see the results, select the blue button Run Query to see the results.
If you see the following error, then navigate back to the file (vpnstatfile.json) in the storage container's blob, and regenerate the SAS URL. Then paste the updated SAS URL in the query.
Save the workbook to return to it later.
The following section shows example log queries to run in your Log Analytics workspace.
AzureDiagnostics
| where Category == "P2SDiagnosticLog" and Message has "Connection successful" and Message has "Username={UserName}"
| project splitted=split(Message, "Username=")
| mv-expand col1=splitted[0], col2=splitted[1], col3=splitted[2]
| project user=split(col2, " ")
| mv-expand username=user[0]
| project ['user']
Note
For some of these queries, the usernames may be obfuscated due to privacy reasons.
AzureDiagnostics
| where Category == "P2SDiagnosticLog" and Message has "EAP authentication succeeded" and Message has "Username={UserName}"
| project Message, MessageFields = split(Message, " "), Userinfo = split (Message, "Username=")
| mv-expand MessageId=MessageFields[2], user=split(Userinfo[1]," ")
| project MessageId, Message, Userinfo[1]
AzureDiagnostics
| where Category == "P2SDiagnosticLog" and Message has "Username={UserName}"
| project Message, MessageFields = split(Message, " "), Userinfo = split (Message, "Username=")
| mv-expand MessageId=MessageFields[2], Username=Userinfo[1]
| project MessageId, Message, Username;
AzureDiagnostics
| where Category == "P2SDiagnosticLog" and Message has "Connection successful"
| project splitted=split(Message, "Username=")
| mv-expand col1=splitted[0], col2=splitted[1], col3=splitted[2]
| project user=split(col2, " ")
| mv-expand username=user[0]
| project-away ['user']
| summarize count() by tostring(username)
| sort by count_ desc
AzureDiagnostics
| where Category == "P2SDiagnosticLog"
| project TimeGenerated, OperationName, Message, Resource, ResourceGroup
| sort by TimeGenerated asc
AzureDiagnostics
| where Category == "P2SDiagnosticLog" and Message has "Connection successful"
| project TimeGenerated, Resource, Message
AzureDiagnostics
| where Category == "P2SDiagnosticLog" and Message has "Connection failed"
| project TimeGenerated, Resource, Message
AzureDiagnostics
| where Category == "P2SDiagnosticLog" and Message has "Connection successful" and Message has "Username={UserName}"| count
AzureDiagnostics
| where Category == "IKEDiagnosticLog"
| project TimeGenerated, OperationName, Message, Resource, ResourceGroup
| sort by TimeGenerated asc
AzureDiagnostics
| where Category == "IKEDiagnosticLog"
| extend Message1=Message
| parse Message with * "Remote " RemoteIP ":" * "500: Local " LocalIP ":" * "500: " Message2
| extend Event = iif(Message has "SESSION_ID", Message2, Message1)
| project TimeGenerated, RemoteIP, LocalIP, Event, Level
| sort by TimeGenerated asc
AzureDiagnostics
| where Category == "P2SDiagnosticLog" and Message has "Statistics"
| project Message, MessageFields = split (Message, " ")
| mv-expand MessageId=MessageFields[2]
| project MessageId, Message;
To learn more about frequently asked questions, see the Virtual WAN FAQ page.