Skip to content

Instantly share code, notes, and snippets.

@AlexAsplund
Last active March 22, 2019 08:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AlexAsplund/d62ff8275768900d07eb7b28fef1b6ef to your computer and use it in GitHub Desktop.
Save AlexAsplund/d62ff8275768900d07eb7b28fef1b6ef to your computer and use it in GitHub Desktop.
<#
.SYNOPSIS
Pulls Azure Identity Risk logs and sends them to a gelf-server through TCP.
.DESCRIPTION
Pulls Azure Identity Risk logs and sends them to a gelf-server.
Requires the PSGelf module (Install-Module -Name PSGELF).
AppCredentials should be supplied as Credential object with AppID as username and AppKey as password.
.EXAMPLE
PS C:\> .\Script.ps1 -AppCredential $Credential -TenantName mytenant.onmicrosoft.com -GelfServer gelf.domain.com -GelfPort <portnumber>
Explanation of what the example does
#>
param(
[parameter(Mandatory)]
[PSCredential]$AppCredential,
[parameter(Mandatory)]
[String]$TenantName,
[parameter(Mandatory)]
[String]$GelfServer,
[parameter(Mandatory)]
[int]$GelfPort
)
$ErrorActionPreference = "STOP"
Import-Module PSGELF
#################################################
# Function for aquiring token
#################################################
<#
.SYNOPSIS
Gets a graph access token
.DESCRIPTION
Gets a graph access token with client credentials.
You need to create a new app in azure AD and supply it [pscredential]$ClientCredential.
Username = application id
Password = Application key/client secret
See MS Graph documentation for beta/identityRiskEvents to give your app the right api-permissions.
.EXAMPLE
PS C:\> Get-MyAADAccessToken -ClientCredential $Credential -TenantName contoso.onmicrosoft.com
Explanation of what the example does
#>
Function Get-MyAADAccessToken {
param(
# application secrets. Username = application id, password = client secret
[parameter(Mandatory)]
[PSCredential]$ClientCredential,
# Name of your tenant. ie contoso.onmicrosoft.com
[parameter(Mandatory)]
[string]$TenantName
)
Add-Type -AssemblyName System.Web
# Decode securestring
$SecureString = [System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($ClientCredential.password)
$Password = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($SecureString)
[System.Runtime.InteropServices.Marshal]::ZeroFreeCoTaskMemUnicode($SecureString)
$BodyList = @(
"client_id=$([System.Web.HttpUtility]::UrlEncode($ClientCredential.UserName))"
"scope=https%3A%2F%2Fgraph.microsoft.com%2F.default"
"client_secret=$([System.Web.HttpUtility]::UrlEncode($Password))",
"grant_type=client_credentials"
)
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"
$PostSplat = @{
ContentType = 'application/x-www-form-urlencoded'
Method = 'POST'
Body = ($BodyList -join '&')
Uri = $Url
}
$Request = Invoke-RestMethod @PostSplat
return $Request
}
#################################################
# Functions for geohash
#################################################
function Create-Geohash($lat,$lng,$precision) {
$minLat = -90
$maxLat = 90
$minLng = -180
$maxLng = 180
$idx = 0
$bit = 0
$geohash=""
while ($geohash.Length -lt $precision) {
$i++
if ($($i%2) -eq 1) { # even bit: longitude
$midpoint = ($minLng + $maxLng) / 2
if ($lng -ge $midpoint) {
$minLng = $midpoint # shrink range down
$idx = $idx*2
} else {
$maxLng = $midpoint # shrink range up
$idx = $idx*2 + 1
}
}else{ #odd bit: latitude
$midpoint = ($minLat + $maxLat) / 2
if ($lat -ge $midpoint) {
$minLat = $midpoint # shrink range down
$idx = $idx*2
} else {
$maxLat = $midpoint # shrink range up
$idx = $idx*2 + 1
}
}
$bit++
if ($bit -eq 5) {
# 5 bits gives us a character: append it and start over
$geohash = $geohash+ $( ToBase32String $idx )
$bit = 0
$idx = 0
}
}
return $geohash
}
function ToBase32String($idx){
$Base32 = "0123456789bcdefghjkmnpqrstuvwxyz"
$varbase32=$Base32[$(($idx) % 32)]
return $varbase32
}
################################################################
# Get last sent event date from file.
# Set date to 2000-01-01 if it does not exist
################################################################
$DatePath = ".\LastIdentityRiskDate.txt"
if(!(test-path $DatePath)){
$LastEvent = Get-Date "2000-01-01"
}
else{
$LastEvent = cat $DatePath | Get-Date
}
# Aquire access token and create header
$AccessToken = (Get-MyAADAccessToken -TenantName $TenantName -ClientCredential $AppCredential).access_token
$Header = @{
Authorization = 'Bearer '+$AccessToken
}
# Get all identity risk events
$Events = @()
$Request = Invoke-RestMethod -Uri 'https://graph.microsoft.com/beta/identityRiskEvents' -Headers $Header
$Events += $Request.value
while($Request.'@odata.nextLink' -ne $null){
$Request = Invoke-RestMethod -Uri $Request.'@odata.nextLink' -Headers $Header
Write-Output $Request.'@odata.nextLink'
$Events += $Request.Value
$More = $Request.'@odata.nextLink' -ne $null
}
# Sort all events and select those that occured after last read event
$NewEvents = $Events | sort riskEventDateTime -Descending | ? {(get-date $_.riskEventDateTime) -gt $LastEvent}
$c = 0
foreach($Event in $NewEvents | select @{Name="Message";Expression={$_.riskEventType}},@{Name='TimeCreated';Expression={$_.riskEventDateTime}},@{Name="Type";Expression={"AzureRiskEvent"}},*){
# Create geohash from found long/lat data
$LocationGeoHash = Create-Geohash -lat (-$Event.location.geoCoordinates.latitude) -lng (-$Event.location.geoCoordinates.longitude) -precision 7
$Event | Add-Member -MemberType NoteProperty -Name LocationGeoHash -Value $LocationGeoHash
if($Event.previousLocation -ne $null){
$PreviousLocationGeoHash = Create-Geohash -lat (-$Event.previousLocation.geoCoordinates.latitude) -lng (-$Event.previousLocation.geoCoordinates.longitude) -precision 7
$Event | Add-Member -MemberType NoteProperty -Name previousLocationGeoHash -Value $PreviousLocationGeoHash
}
# Add geohash
$Event | Add-Member -MemberType NoteProperty -Name geoHashMetricSize -Value 153
# Send to gelf-server
Send-PSGelfTCPFromObject -GelfServer $GelfServer -Port $GelfPort -GelfMessage $Event -Verbose
$c++
}
# Select last event
$LastEventString = $Events.riskEventDateTime | sort -Descending | select -first 1
if($c -gt 0){
if($LastEventString -eq $null){
throw "Error saving last event date"
}
# Save last event to file
$LastEventString | Out-File $DatePath
}
Write-Output "Sent $c events to graylog"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment