From d15fc821c64c93d6544c33c358651b1b6cd072df Mon Sep 17 00:00:00 2001 From: robbwilcox Date: Sat, 5 Oct 2024 12:23:48 -0500 Subject: [PATCH] Copy Azure Role scripts --- Check-AppRoles.ps1 | 117 +++++++++++++++++++++++++++++++ Get-AzureRoles.ps1 | 30 ++++++++ Hello.ps1 | 1 + clean_csv.ps1 | 14 ++++ parse_logs.ps1 | 95 +++++++++++++++++++++++++ permissions_analysis_results.txt | Bin 0 -> 23292 bytes required_roles.txt | 14 ++++ 7 files changed, 271 insertions(+) create mode 100644 Check-AppRoles.ps1 create mode 100644 Get-AzureRoles.ps1 create mode 100644 Hello.ps1 create mode 100644 clean_csv.ps1 create mode 100644 parse_logs.ps1 create mode 100644 permissions_analysis_results.txt create mode 100644 required_roles.txt diff --git a/Check-AppRoles.ps1 b/Check-AppRoles.ps1 new file mode 100644 index 0000000..025f130 --- /dev/null +++ b/Check-AppRoles.ps1 @@ -0,0 +1,117 @@ +[CmdletBinding()] +param( + [Parameter(Mandatory=$true)] + [string]$InputFile +) + +# Ensure you're logged into Azure CLI +try { + $null = az account show +} +catch { + Write-Host "Please log in to Azure CLI first using 'az login'" + exit +} + +# Function to get all role definitions +function Get-AllRoleDefinitions { + $roles = az role definition list | + ConvertFrom-Json | + ForEach-Object { $_ } | +# Where-Object { $_.roleName -eq "Website Contributor" } + Where-Object { $_.roleType -ne "CustomRole" -and $_.roleName -ne "Contributor" -and $_.roleName -ne "Owner" } + return $roles +} + +# Function to check if a string matches a resource type pattern +function Test-ResourceTypeMatch { + param ( + [string]$Pattern, + [string]$ResourceType + ) + $patternParts = $Pattern -split '/' + $resourceTypeParts = $ResourceType -split '/' + + for ($i = 0; $i -lt $patternParts.Count; $i++) { + if ($i -ge $resourceTypeParts.Count -and $patternParts[$i] -ne "*") { + return $false + } + + if ($patternParts[$i] -eq '*') { + if ($i -eq $patternParts.Count - 1) { + return $true + } + continue + } + + if ($patternParts[$i] -ne $resourceTypeParts[$i]) { + return $false + } + } + + # If the pattern is shorter than the resource type, it's only a match if the last part was a wildcard + return ($patternParts.Count -eq $resourceTypeParts.Count) -or ($patternParts[-1] -eq '*') +} + +# Function to check if a role grants access to a resource type +function Test-RoleAccess { + param ( + $Role, + $ResourceType + ) + $hasAccess = $false + foreach ($permission in $Role.permissions) { + # Check actions and dataActions + foreach ($action in ($permission.actions + $permission.dataActions)) { + if (Test-ResourceTypeMatch -Pattern $action -ResourceType $ResourceType) { + $hasAccess = $true + break + } + } + + # Check notActions and notDataActions + foreach ($notAction in ($permission.notActions + $permission.notDataActions)) { + if (Test-ResourceTypeMatch -Pattern $notAction -ResourceType $ResourceType) { + return $false # Explicitly not allowed + } + } + + if ($hasAccess) { + break + } + } + return $hasAccess +} + +# Get all role definitions +$allRoles = Get-AllRoleDefinitions + +# Read the file with resource types +try { + $resourceTypes = Get-Content -Path $InputFile -ErrorAction Stop + $resourceTypes = $resourceTypes | Sort-Object +} +catch { + Write-Host "Error reading input file: $_" + exit +} + +# Process each resource type +foreach ($resourceType in $resourceTypes) { + Write-Host "Resource Type: $resourceType" + $matchingRoles = @() + + foreach ($role in $allRoles) { + if (Test-RoleAccess -Role $role -ResourceType $resourceType) { + $matchingRoles += $role.roleName + } + } + + if ($matchingRoles.Count -gt 0) { + Write-Host "Roles granting access:" + $matchingRoles | ForEach-Object { Write-Host " - $_" } + } else { + Write-Host "No roles found granting access to this resource type." + } + Write-Host "" +} \ No newline at end of file diff --git a/Get-AzureRoles.ps1 b/Get-AzureRoles.ps1 new file mode 100644 index 0000000..05cbd7c --- /dev/null +++ b/Get-AzureRoles.ps1 @@ -0,0 +1,30 @@ +# NOTE: +# Make sure you are logged into the az cli before running this +# Command: az login + +# Get the JSON data from Azure CLI +$jsonData = az role definition list | ConvertFrom-Json + +# Create an empty array to store the formatted strings +$formattedRoles = @() + +foreach ($role in $jsonData) { + $roleType = if ($role.roleType -eq "BuiltInRole") { "Built-in role" } else { "Custom role" } + + $formattedRole = @" + +$roleType $($role.roleName) +Description $($role.description) +ID $($role.name) +"@ + + $formattedRoles += $formattedRole +} + +# Join all formatted roles into a single string +$output = $formattedRoles -join "`n" + +# Write the output to a text file +$output | Out-File -FilePath "azure_roles.txt" -Encoding UTF8 + +Write-Host "Azure roles have been written to azure_roles.txt" \ No newline at end of file diff --git a/Hello.ps1 b/Hello.ps1 new file mode 100644 index 0000000..eff826d --- /dev/null +++ b/Hello.ps1 @@ -0,0 +1 @@ +Write-Host "Hello World!" -ForegroundColor Blue \ No newline at end of file diff --git a/clean_csv.ps1 b/clean_csv.ps1 new file mode 100644 index 0000000..a25003d --- /dev/null +++ b/clean_csv.ps1 @@ -0,0 +1,14 @@ +# Parameters +$inputFilePath = "./QueryResult.csv" +$outputFilePath = "./CleanResults.csv" + +# Read the content of the file +$content = Get-Content -Path $inputFilePath -Raw + +# Remove all double quotes +$contentWithoutQuotes = $content -replace '"', '' + +# Write the modified content to a new file +$contentWithoutQuotes | Set-Content -Path $outputFilePath -NoNewline + +Write-Output "Quotes removed. New file saved as: $outputFilePath" \ No newline at end of file diff --git a/parse_logs.ps1 b/parse_logs.ps1 new file mode 100644 index 0000000..194d6ec --- /dev/null +++ b/parse_logs.ps1 @@ -0,0 +1,95 @@ +param( + [string]$CsvPath = "path_to_your_csv_file.csv", + [int]$RowLimit = -1, # -1 means process all rows + [string]$ApplicationName = "" +) + +# Function to import CSV data with optional row limit +function Import-LimitedCsv { + param( + [string]$Path, + [int]$Limit = -1 + ) + + $csv = Import-Csv -Path $Path + if ($Limit -gt 0) { + return $csv | Select-Object -First $Limit + } + return $csv +} + +function Write-OutputBoth { + param( + [string]$Message, + [System.IO.StreamWriter]$Writer + ) + Write-Host $Message + $Writer.WriteLine($Message) +} + +$outputFileName = if ($ApplicationName) { + "$($ApplicationName.Replace(' ', '_').ToLower())_results.txt" +} else { + "all_applications_results.txt" +} + +$outputDir = "output" +if (-not (Test-Path -Path $outputDir)) { + New-Item -ItemType Directory -Force -Path $outputDir +} + +$outputFilePath = Join-Path $outputDir $outputFileName + +# Import the CSV file with optional row limit +$csvData = Import-LimitedCsv -Path $CsvPath -Limit $RowLimit + +# Define operations to ignore +$ignoredOperations = @("Resume Databases", "UpdateWebSite") + +# Filter out items with "Started" status and group by "Event initiated by" +$groupedData = $csvData | + Where-Object { $_."Status" -ne "Started" -and $_."Operation name" -notin $ignoredOperations } | + Group-Object -Property "Event initiated by" + +if ($ApplicationName) { + $groupedData = $groupedData | Where-Object { $_.Name -eq $ApplicationName } +} + +$writer = [System.IO.StreamWriter]::new("$OutputFilePath.raw") + +try { + # Process each group + foreach ($group in $groupedData) { + Write-Host "Application: $($group.Name)" + Write-Host "------------------------" + + $resourceTypes = $group.Group | + Select-Object "Resource type", "Operation name" -Unique | + Group-Object -Property "Resource type" + + foreach ($resourceType in $resourceTypes) { + Write-OutputBoth "$($resourceType.Name)" $writer + } + Write-Host "" + } + + $totalRows = $csvData.Count + $processedRows = ($csvData | Where-Object { $_."Status" -ne "Started" -and $_."Operation name" -notin $ignoredOperations}).Count + if ($ApplicationName) { + $processedRows = ($groupedData | Where-Object { $_.Name -eq $ApplicationName }).Group.Count + } + $skippedRows = $totalRows - $processedRows + + Write-Host "Total rows in CSV: $totalRows" + Write-Host "Rows processed: $processedRows" + Write-Host "Rows skipped (Started status, ignored operations, or non-matching application): $skippedRows" + Write-Host "Ignored operations: $($ignoredOperations -join ', ')" + if ($ApplicationName) { + Write-Host "Filtered by application: $ApplicationName" + } + Write-Host "" + Write-Host "Results have been saved to: $outputFileName" +} +finally { + $writer.Close() +} \ No newline at end of file diff --git a/permissions_analysis_results.txt b/permissions_analysis_results.txt new file mode 100644 index 0000000000000000000000000000000000000000..9368900c19f6656b2e7903d64b095eb1795a1b4e GIT binary patch literal 23292 zcmeHPU3c0>5Z&jV)Bm71+J{8%eRJb{owiPDn)n$5Ce#>Qz)74R-}c@e*4mZCvCJ|O zLOD5!6(MV9?#}nj^54G~W?+_PZl?GiIOTGpU*f%{YQ&C)G&qz^Qo;GHXcI>8z@c-I`iu>zGpnjef70xv8tM3G#Ox&)No z0yTF}t_HY2#OE`Mu8$(=9N{+>7MnHb-5sU3c$XmX$?~3V=opw6C2POTt*njJ@8EC+ zx)SWh*j(c03HZLny~Mn-vXzsGe9HnL`lw@mGBtxRg=i7V7EBOd}8 z8DJ-f#y6lq-QYFleX-F{r*Y>NrAypjnCmDs%HE$sW{azyKyE3yv<1{B>Km^e71~ns z-qJ*QsEX35=|kRopjC8^bc;2Jk)IgEh~FHRjJAn8OxqxPs*PUH?&-+N{98~!yT3Ls z%~#x^~TuZt{N^e7P^h7WPRWPd{w@y zdi-cSZkMWdqgZ_yLieP97KdE1J6Ek|rzT~sGi1gwO(Ps%!s(s4R& zjGB!FWIsM4$Gn5(TiZ^YyVmZzh2C5!VHd`&AEOaX^3`;`qgmd$ds6Y`{%Q46o8&Q! z5{^f1L%#I9`fqsYOGxty{+fPlWUXavZn3M+PL0sh&rzdouS4uuLCyCu zs^Xc)k$#@BBqQ$_tAB!hVcsXxi*5>#7Ab!>thBN(l&47>&A90$<|dqHR#6SkaeUNmmMeHyg!4E2L}h$nNiu5J=iW)SzI zC+^*0wN*FQ^n0()3Q#XNzetRC@1{Sc*XmZL?75XSd#mg()83t9UniSue~R=kP;rgV zXg7`(gV17Jfa4{2&gMH}_j^X<0pzF?xc18d=$AJiv1#`|GH4LYb39oG2I-)=3d@3RQWULW-vNZEZOTwL>qf zlh~W~@9@vzgc4LWYZ-zw?zY5PQ|vzDiRLqxGP>%Os+e5xGZ3W23=o&d`LgB_&C{ff zW>|TtDvx<84?!05G-)H}dY|D0T>i8|V$Ze6Ss&(4%w}Su0+)TWuJHKjl@!l>wNFa+ z#?`fP39Wvaett(RJ5$JMTlxg?**qO_3VXzpA?$#&Lno(EV`L^KlFUwP`qXI4kRM@6 z&Gwn?&dh*EZ0(b?vDBitDV@~jHuoM?+L)B-)g5@rPW3WI2v0Dx8^TC&4t}LJHH2JA zwbNCqVkE1Wjg+m}2VHCYVGU`5)pfJ+FlS~5*q5dO5Npe9GSnFAkt>t1Fkb!B z>R+r5QXZY9w6lZO$omJ?m3k&89t~ck)Gb{hhb)|Ykt0$TE?lqC8 zqU0#cqoiwhLrYQgMcMh27%e)tXl8Md^v~{~E$pH(o4d81Mk3wRN~rG>Gb*&@B+RVp z{Kk#8V)R{RLYdibJ-Mw?QC{WU-I}%)2i?fEt*9`k(CkaM6_>~S4ZkmkkyICbaUY#{ z#)?vHk(ql|WTaNb+B)Moe%fu61QE$s@~6eRC^vc?thQR2s{Mlfoi}JJQcvj>cTu-w zI*6W}eT^<6;O2MsGda{&Jt=-4Ntb0oD(3r{C2gxjZ12_hXGFUwC8w~K><+~6PIUcm zLuCJk@2s~vb_Scj#>6Zm@N2}~>?_d^$h0%RDJh1>@a-wy?XOl`OPhCg8kTl`OM1Ng zHevRCvlGCaAk#kG!|L@Ac@Qhqu3E}|6SE&;Kl0AQ)rm+R2Yvm2{4Dh2SZ$}$RqwNT GyZ-?(iJEQz literal 0 HcmV?d00001 diff --git a/required_roles.txt b/required_roles.txt new file mode 100644 index 0000000..c0dcc72 --- /dev/null +++ b/required_roles.txt @@ -0,0 +1,14 @@ +Minimal set of Azure roles required: +----------------------------------- +Role Name: Disk Encryption Set Operator for Managed Disks +Description: Provides permissions to read, write or delete disk encryption sets which are used for encrypting managed disks with customer managed keys +ID: 136d308c-0937-4a49-9bd7-edfb42adbffc + +Role Name: Managed Identity Contributor +Description: Create, Read, Update, and Delete User Assigned Identity +ID: e40ec5ca-96e0-45a2-b4ff-59039f2c2b59 + +Role Name: Desktop Virtualization Power On Contributor +Description: Provide permission to the Azure Virtual Desktop Resource Provider to start virtual machines. +ID: 489581de-a3bd-480d-9518-53dea7416b33 +