흐름 로그 읽기
중요
2027년 9월 30일에 NSG(네트워크 보안 그룹) 흐름 로그가 사용 중지됩니다. 이러한 사용 중지의 일환으로 2025년 6월 30일부터 새로운 NSG 흐름 로그를 더 이상 만들 수 없습니다. NSG 흐름 로그의 제한을 극복하는 가상 네트워크 흐름 로그로 마이그레이션하는 것이 좋습니다. 사용 중지일 이후에는 NSG 흐름 로그를 사용한 트래픽 분석이 더 이상 지원되지 않으며, 구독에 포함된 기존 NSG 흐름 로그 리소스는 삭제됩니다. 그러나 NSG 흐름 로그 레코드는 삭제되지 않으며 각각의 보존 정책을 계속 따릅니다. 자세한 내용은 공식 공지를 참조하세요.
이 문서에서는 전체 로그를 구문 분석할 필요 없이 PowerShell을 사용하여 Azure Network Watcher 흐름 로그의 일부를 선택적으로 읽는 방법을 알아봅니다. 흐름 로그는 스토리지 계정의 블록 Blob에 저장됩니다. 각 로그는 매시간 생성되고 몇 분마다 최신 데이터로 업데이트되는 별도의 블록 Blob입니다. 이 문서에 제공된 스크립트를 사용하면 전체 로그를 다운로드하지 않고도 흐름 로그에서 최신 데이터를 읽을 수 있습니다.
이 문서에서 설명하는 개념은 PowerShell에만 국한되지 않고 Azure Storage API에서 지원하는 모든 언어에 적용됩니다.
활성 구독이 있는 Azure 계정. 체험 계정을 만듭니다.
컴퓨터에 PowerShell이 설치되어 있습니다. 자세한 내용은 Windows, Linux 및 macOS에 PowerShell 설치를 참조하세요. 이 문서에는 Az PowerShell 모듈이 필요합니다. 자세한 내용은 Azure PowerShell 설치 방법을 참조하세요. 설치되어 있는 버전을 확인하려면
Get-Module -ListAvailable Az
을 실행합니다.하나 이상의 지역에 있는 흐름 로그입니다. 자세한 내용은 네트워크 보안 그룹 흐름 로그 만들기 또는 가상 네트워크 흐름 로그 만들기를 참조하세요.
흐름 로그 및 스토리지 계정 구독에 필요한 RBAC 권한입니다. 자세한 내용은 Network Watcher RBAC 권한을 참조하세요.
다음 PowerShell 스크립트는 네트워크 보안 그룹 흐름 로그 Blob을 쿼리하고 CloudBlockBlob 블록 Blob 내의 블록을 나열하는 데 필요한 변수를 설정합니다. 사용자 환경에 유효한 값, 특히 "yourSubscriptionId", "FLOWLOGSVALIDATIONWESTCENTRALUS", "V2VALIDATIONVM-NSG", "yourStorageAccountName", "ml-rg", "000D3AF87856", "11/11/2018 03:00"을 포함하도록 스크립트를 업데이트합니다. 예를 들어, yourSubscriptionId는 구독 ID로 바꿔야 합니다.
function Get-NSGFlowLogCloudBlockBlob {
[CmdletBinding()]
param (
[string] [Parameter(Mandatory=$true)] $subscriptionId,
[string] [Parameter(Mandatory=$true)] $NSGResourceGroupName,
[string] [Parameter(Mandatory=$true)] $NSGName,
[string] [Parameter(Mandatory=$true)] $storageAccountName,
[string] [Parameter(Mandatory=$true)] $storageAccountResourceGroup,
[string] [Parameter(Mandatory=$true)] $macAddress,
[datetime] [Parameter(Mandatory=$true)] $logTime
)
process {
# Retrieve the primary storage account key to access the network security group logs
$StorageAccountKey = (Get-AzStorageAccountKey -ResourceGroupName $storageAccountResourceGroup -Name $storageAccountName).Value[0]
# Setup a new storage context to be used to query the logs
$ctx = New-AzStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageAccountKey
# Container name used by network security group flow logs
$ContainerName = "insights-logs-networksecuritygroupflowevent"
# Name of the blob that contains the network security group flow log
$BlobName = "resourceId=/SUBSCRIPTIONS/${subscriptionId}/RESOURCEGROUPS/${NSGResourceGroupName}/PROVIDERS/MICROSOFT.NETWORK/NETWORKSECURITYGROUPS/${NSGName}/y=$($logTime.Year)/m=$(($logTime).ToString("MM"))/d=$(($logTime).ToString("dd"))/h=$(($logTime).ToString("HH"))/m=00/macAddress=$($macAddress)/PT1H.json"
# Gets the storage blog
$Blob = Get-AzStorageBlob -Context $ctx -Container $ContainerName -Blob $BlobName
# Gets the block blog of type 'Microsoft.Azure.Storage.Blob.CloudBlob' from the storage blob
$CloudBlockBlob = [Microsoft.Azure.Storage.Blob.CloudBlockBlob] $Blob.ICloudBlob
#Return the Cloud Block Blob
$CloudBlockBlob
}
}
function Get-NSGFlowLogBlockList {
[CmdletBinding()]
param (
[Microsoft.Azure.Storage.Blob.CloudBlockBlob] [Parameter(Mandatory=$true)] $CloudBlockBlob
)
process {
# Stores the block list in a variable from the block blob.
$blockList = $CloudBlockBlob.DownloadBlockListAsync()
# Return the Block List
$blockList
}
}
$CloudBlockBlob = Get-NSGFlowLogCloudBlockBlob -subscriptionId "yourSubscriptionId" -NSGResourceGroupName "FLOWLOGSVALIDATIONWESTCENTRALUS" -NSGName "V2VALIDATIONVM-NSG" -storageAccountName "yourStorageAccountName" -storageAccountResourceGroup "ml-rg" -macAddress "000D3AF87856" -logTime "11/11/2018 03:00"
$blockList = Get-NSGFlowLogBlockList -CloudBlockBlob $CloudBlockBlob
$blockList
변수는 Blob의 블록 목록을 반환합니다. 각 블록 Blob에는 블록이 두 개 이상 포함되어 있습니다. 첫 번째 블록의 길이는 12바이트이며 JSON 로그의 왼쪽 괄호를 포함합니다. 나머지 블록은 닫는 괄호이며 길이가 2바이트입니다. 다음 로그 예에는 7개의 개별 항목이 있습니다. 로그의 모든 새 항목은 최종 블록 앞의 오른쪽 끝에 추가됩니다.
Name Length Committed
---- ------ ---------
ZDk5MTk5N2FkNGE0MmY5MTk5ZWViYjA0YmZhODRhYzY= 12 True
NzQxNDA5MTRhNDUzMGI2M2Y1MDMyOWZlN2QwNDZiYzQ= 2685 True
ODdjM2UyMWY3NzFhZTU3MmVlMmU5MDNlOWEwNWE3YWY= 2586 True
ZDU2MjA3OGQ2ZDU3MjczMWQ4MTRmYWNhYjAzOGJkMTg= 2688 True
ZmM3ZWJjMGQ0ZDA1ODJlOWMyODhlOWE3MDI1MGJhMTc= 2775 True
ZGVkYTc4MzQzNjEyMzlmZWE5MmRiNjc1OWE5OTc0OTQ= 2676 True
ZmY2MjUzYTIwYWIyOGU1OTA2ZDY1OWYzNmY2NmU4ZTY= 2777 True
Mzk1YzQwM2U0ZWY1ZDRhOWFlMTNhYjQ3OGVhYmUzNjk= 2675 True
ZjAyZTliYWE3OTI1YWZmYjFmMWI0MjJhNzMxZTI4MDM= 2 True
이 섹션에서는 $blocklist
변수를 읽어 데이터를 검색합니다. 다음 예에서는 블록 목록을 반복하여 각 블록에서 바이트를 읽고 이를 배열에 저장합니다. 이때 DownloadRangeToByteArray 메서드를 사용하여 데이터를 검색합니다.
function Get-NSGFlowLogReadBlock {
[CmdletBinding()]
param (
[System.Array] [Parameter(Mandatory=$true)] $blockList,
[Microsoft.Azure.Storage.Blob.CloudBlockBlob] [Parameter(Mandatory=$true)] $CloudBlockBlob
)
# Set the size of the byte array to the largest block
$maxvalue = ($blocklist | measure Length -Maximum).Maximum
# Create an array to store values in
$valuearray = @()
# Define the starting index to track the current block being read
$index = 0
# Loop through each block in the block list
for($i=0; $i -lt $blocklist.count; $i++)
{
# Create a byte array object to story the bytes from the block
$downloadArray = New-Object -TypeName byte[] -ArgumentList $maxvalue
# Download the data into the ByteArray, starting with the current index, for the number of bytes in the current block. Index is increased by 3 when reading to remove preceding comma.
$CloudBlockBlob.DownloadRangeToByteArray($downloadArray,0,$index, $($blockList[$i].Length)) | Out-Null
# Increment the index by adding the current block length to the previous index
$index = $index + $blockList[$i].Length
# Retrieve the string from the byte array
$value = [System.Text.Encoding]::ASCII.GetString($downloadArray)
# Add the log entry to the value array
$valuearray += $value
}
#Return the Array
$valuearray
}
$valuearray = Get-NSGFlowLogReadBlock -blockList $blockList -CloudBlockBlob $CloudBlockBlob
이제 $valuearray
배열에는 각 블록의 문자열 값이 포함되어 있습니다. 항목을 확인하려면 $valuearray[$valuearray.Length-2]
를 실행하여 배열의 마지막에서 두 번째 값을 가져옵니다. 마지막 값은 닫는 괄호이므로 필요하지 않습니다.
이 값의 결과가 다음 예제에 나와 있습니다.
{
"records": [
{
"time": "2017-06-16T20:59:43.7340000Z",
"systemId": "abcdef01-2345-6789-0abc-def012345678",
"category": "NetworkSecurityGroupFlowEvent",
"resourceId": "/SUBSCRIPTIONS/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/RESOURCEGROUPS/MYRESOURCEGROUP/PROVIDERS/MICROSOFT.NETWORK/NETWORKSECURITYGROUPS/MYNSG",
"operationName": "NetworkSecurityGroupFlowEvents",
"properties": {
"Version": 1,
"flows": [
{
"rule": "DefaultRule_AllowInternetOutBound",
"flows": [
{
"mac": "000D3A18077E",
"flowTuples": [
"1497646722,10.0.0.4,168.62.32.14,44904,443,T,O,A",
"1497646722,10.0.0.4,52.240.48.24,45218,443,T,O,A",
"1497646725,10.0.0.4,168.62.32.14,44910,443,T,O,A",
"1497646725,10.0.0.4,52.240.48.24,45224,443,T,O,A",
"1497646728,10.0.0.4,168.62.32.14,44916,443,T,O,A",
"1497646728,10.0.0.4,52.240.48.24,45230,443,T,O,A",
"1497646732,10.0.0.4,168.62.32.14,44922,443,T,O,A",
"1497646732,10.0.0.4,52.240.48.24,45236,443,T,O,A"
]
}
]
},
{
"rule": "DefaultRule_DenyAllInBound",
"flows": []
},
{
"rule": "UserRule_ssh-rule",
"flows": []
},
{
"rule": "UserRule_web-rule",
"flows": [
{
"mac": "000D3A18077E",
"flowTuples": [
"1497646738,13.82.225.93,10.0.0.4,1180,80,T,I,A",
"1497646750,13.82.225.93,10.0.0.4,1184,80,T,I,A",
"1497646768,13.82.225.93,10.0.0.4,1181,80,T,I,A",
"1497646780,13.82.225.93,10.0.0.4,1336,80,T,I,A"
]
}
]
}
]
}
}
]
}