Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BugFix] - Suspended Main Runbooks and Missing GR13 Compliance Results #392

Merged
merged 16 commits into from
Feb 10, 2025
Binary file modified psmodules/Check-StorageAccountTLSversion.zip
Binary file not shown.
Binary file modified psmodules/Monitor-BreakGlassAccount.zip
Binary file not shown.
24 changes: 22 additions & 2 deletions setup/IaC/modules/automationaccount.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ resource guardrailsAC 'Microsoft.Automation/automationAccounts@2021-06-22' = if
properties: {
contentLink: {
uri: '${ModuleBaseURL}/Monitor-BreakGlassAccount.zip'
version: '1.0.1'
version: '1.0.2'
}
}
}
Expand Down Expand Up @@ -392,7 +392,7 @@ resource guardrailsAC 'Microsoft.Automation/automationAccounts@2021-06-22' = if
properties: {
contentLink: {
uri: '${ModuleBaseURL}/Check-StorageAccountTLSversion.zip'
version: '1.0.0'
version: '1.0.2'
}
}
}
Expand Down Expand Up @@ -477,6 +477,26 @@ resource guardrailsAC 'Microsoft.Automation/automationAccounts@2021-06-22' = if
}
}

resource module50 'modules' = if (newDeployment || updatePSModules) {
name: 'Az.ResourceGraph'
properties: {
contentLink: {
uri: 'https://devopsgallerystorage.blob.core.windows.net:443/packages/az.resourcegraph.1.1.0.nupkg'
version: '1.1.0'
}
}
}

resource module51 'modules' = if (newDeployment || updatePSModules) {
name: 'Az.Accounts'
properties: {
contentLink: {
uri: 'https://devopsgallerystorage.blob.core.windows.net:443/packages/az.accounts.4.0.2.nupkg'
version: '4.0.2'
}
}
}

resource variable1 'variables' = if (newDeployment || updateCoreResources) {
name: 'KeyvaultName'
properties: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
RootModule = 'Monitor-BreakGlassAccount'

# Version number of this module.
ModuleVersion = '1.0.1'
ModuleVersion = '1.0.2'

# Supported PSEditions
# CompatiblePSEditions = @()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,24 +187,28 @@ function Test-BreakGlassAccounts {
}

# Retrieve the log data and check the data retention period for sign in
$kqlQuery = "SigninLogs
| where TimeGenerated > ago(365d)
| order by TimeGenerated desc"
$kqlQuery = @"
SigninLogs
| where UserPrincipalName in ('$($FirstBreakGlassUPN)', '$($SecondBreakGlassUPN)')
| project TimeGenerated, UserPrincipalName, CreatedDateTime
| where TimeGenerated > ago(365d)
| order by TimeGenerated desc
"@

try{
$workspace = Get-AzOperationalInsightsWorkspace -ResourceGroupName $resourceGroupName -Name $workspaceId
$queryResults = Invoke-AzOperationalInsightsQuery -WorkspaceId $workspace.CustomerId -Query $kqlQuery
try {
$workspace = Get-AzOperationalInsightsWorkspace -ResourceGroupName $resourceGroupName -Name $workspaceId
$queryResults = Invoke-AzOperationalInsightsQuery -WorkspaceId $workspace.CustomerId -Query $kqlQuery -ErrorAction Stop

# Access the Results property of the query output
$results = $queryResults.Results

$BGdata = $queryResults.Results | Where-Object {$_.UserPrincipalName -eq $FirstBreakGlassUPN -or $_.UserPrincipalName -eq $SecondBreakGlassUPN}

# check break glass account signin
$dataMostRecentSignInFirstBG = $BGdata | Where-Object {$_.UserPrincipalName -eq $FirstBreakGlassUPN} | Sort-Object TimeGenerated -Descending
$dataMostRecentSignInSecondBG = $BGdata | Where-Object {$_.UserPrincipalName -eq $SecondBreakGlassUPN} | Sort-Object createdDateTime -Descending
# check break glass account signin
$dataMostRecentSignInFirstBG = $results | Where-Object {$_.UserPrincipalName -eq $FirstBreakGlassUPN} | Select-Object -First 1
$dataMostRecentSignInSecondBG = $results | Where-Object {$_.UserPrincipalName -eq $SecondBreakGlassUPN} | Select-Object -First 1

if ($null -ne $dataMostRecentSignInFirstBG -and $null -ne $dataMostRecentSignInSecondBG ){
$IsCompliant = $true
}

if ($null -ne $dataMostRecentSignInFirstBG -or $null -ne $dataMostRecentSignInSecondBG) {
$IsCompliant = $true
}
}
catch {
if ($null -eq $workspace) {
Expand All @@ -220,7 +224,6 @@ function Test-BreakGlassAccounts {
$IsCompliant = $false
Write-Host "Error occurred retrieving the sign-in log data: $_"
}

}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
RootModule = 'Check-StorageAccountTLSversion'

# Version number of this module.
ModuleVersion = '1.0.1'
ModuleVersion = '1.0.2'

# Supported PSEditions
# CompatiblePSEditions = @()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,126 +3,149 @@ function Check-TLSversion {
[System.Object] $objList
)

Write-Verbose "Starting subscription access verification..."

$storageAccountList = @()
foreach ($obj in $objList)
{
Write-Host "Find compliance details for Subscription : $($obj.Name)"
$subscription = @()
$subscription += New-Object -TypeName psobject -Property ([ordered]@{'DisplayName'=$obj.Name;'SubscriptionID'=$obj.Id})

$currentSubscription = Get-AzContext
if($currentSubscription.Subscription.Id -ne $subscription.SubscriptionId){
# Set Az context to the this subscription
Set-AzContext -SubscriptionId $subscription.SubscriptionID
Write-Host "AzContext set to $($subscription.DisplayName)"
}

$resourceGroups = Get-AzResourceGroup

# Loop through each resource group
foreach ($resourceGroup in $resourceGroups) {
$storageAccounts = Get-AzStorageAccount -ResourceGroupName $resourceGroup.ResourceGroupName
if ($storageAccounts.Count -ne 0){
foreach ($storageAccount in $storageAccounts) {
$TLSversionNumeric = $storageAccount.MinimumTlsVersion -replace "TLS", "" -replace "_", "."
$storageAccInfo = [PSCustomObject]@{
SubscriptionName = $obj.Name
ResourceGroupName = $resourceGroup.ResourceGroupName
StorageAccountName = $storageAccount.StorageAccountName
MinimumTlsVersion = $storageAccount.MinimumTlsVersion
TLSversionNumeric = $TLSversionNumeric
}
$storageAccountList += $storageAccInfo
Write-Verbose "Processing Subscription: $($obj.Name) ($($obj.Id))"

try {
# Simplified query to match exactly what we see in Resource Graph
$query = @"
resources
| where type =~ 'Microsoft.Storage/storageAccounts'
| where subscriptionId =~ '$($obj.Id)'
| extend minimumTlsVersion = properties.minimumTlsVersion
| project subscriptionId,
resourceGroup = resourceGroup,
name,
minimumTlsVersion
"@

Write-Verbose "Executing Resource Graph query for subscription: $($obj.Id)"
$storageAccounts = Search-azgraph -Query $query -ErrorAction Stop
Write-Verbose "Found $($storageAccounts.Count) storage accounts in subscription"

foreach ($storageAcc in $storageAccounts) {
Write-Verbose "Processing storage account: $($storageAcc.name)"
$TLSversionNumeric = $storageAcc.minimumTlsVersion -replace "TLS", "" -replace "_", "."
$storageAccInfo = [PSCustomObject]@{
SubscriptionName = $obj.Name
ResourceGroupName = $storageAcc.resourceGroup
StorageAccountName = $storageAcc.name
MinimumTlsVersion = $storageAcc.minimumTlsVersion
TLSversionNumeric = $TLSversionNumeric
}
$storageAccountList += $storageAccInfo
}
}
catch {
Write-Warning "Failed to query storage accounts for subscription '$($obj.Name)': $_"
continue
}
}

if ($storageAccountList.Count -eq 0) {
Write-Verbose "No storage accounts found. Current subscription context: $((Get-AzContext).Subscription.Id)"
Write-Verbose "Number of subscriptions checked: $($objList.Count)"
Write-Verbose "Subscription IDs checked: $($objList.Id -join ', ')"
}

Write-Verbose "Total storage accounts found across all subscriptions: $($storageAccountList.Count)"
return $storageAccountList
}

function Verify-TLSForStorageAccount {
param (
[string] $ControlName,
[string] $ItemName,
[hashtable] $msgTable,
[Parameter(Mandatory=$true)]
[string] $ReportTime,
[string] $itsgcode,
[string] $CloudUsageProfiles = "3", # Passed as a string
[string] $ModuleProfiles, # Passed as a string
[switch] $EnableMultiCloudProfiles # New feature flag, default to false
[string] $ControlName,
[string] $ItemName,
[hashtable] $msgTable,
[Parameter(Mandatory=$true)]
[string] $ReportTime,
[string] $itsgcode,
[string] $CloudUsageProfiles = "3",
[string] $ModuleProfiles,
[switch] $EnableMultiCloudProfiles
)

# Initialize all arrays and objects at the start
$IsCompliant = $false
[PSCustomObject] $PSObjectList = New-Object System.Collections.ArrayList
[PSCustomObject] $ErrorList = New-Object System.Collections.ArrayList

$PSObjectList = @()
$ErrorList = [System.Collections.ArrayList]::new()
$AdditionalResults = @()
$commentsArray = @()

# Initialize moduleOutput at the start
$moduleOutput = [PSCustomObject]@{
ComplianceResults = $null
Errors = $ErrorList
AdditionalResults = $AdditionalResults
}

#Check Subscriptions
try {
$objs = Get-AzSubscription -ErrorAction Stop | Where-Object {$_.State -eq "Enabled"}
if (-not $objs) {
$errorMsg = "No enabled subscriptions found"
$ErrorList.Add($errorMsg) | Out-Null
Write-Warning $errorMsg
return $moduleOutput
}
}
catch {
$Errorlist.Add("Failed to execute the 'Get-AzSubscription' command--verify your permissions and the installion of the Az.Resources module; returned error message: $_")
throw "Error: Failed to execute the 'Get-AzSubscription' command--verify your permissions and the installion of the Az.Resources module; returned error message: $_"
$errorMsg = "Failed to execute the 'Get-AzSubscription' command--verify your permissions and the installation of the Az.Resources module; returned error message: $_"
$ErrorList.Add($errorMsg) | Out-Null
Write-Warning $errorMsg
return $moduleOutput
}

$PSObjectList = @()
try{
try {
$PSObjectList = Check-TLSversion -objList $objs
if ($null -eq $PSObjectList) {
$errorMsg = "No storage accounts found to evaluate"
$ErrorList.Add($errorMsg) | Out-Null
Write-Warning $errorMsg
return $moduleOutput
}

# Filter to keep only objects that have the 'subscriptionName' property
$PSObjectListCleaned = $PSObjectList | Where-Object { $_.PSObject.Properties["MinimumTlsVersion"] }

# find TLS version not equal to TLS1.2
$filteredPSObjectList = $PSObjectListCleaned | Where-Object { $_.MinimumTlsVersion -ne "TLS1_2" }
# Filter valid objects and check TLS compliance in one pass
$nonCompliantAccounts = $PSObjectList |
Where-Object { $_.PSObject.Properties["MinimumTlsVersion"] } |
Where-Object {
$_.MinimumTlsVersion -ne "TLS1_2" -and
$_.TLSversionNumeric -lt 1.2
}

# Condition: all storage accounts are using TLS1.2
if ($filteredPSObjectList.Count -eq 0){
if ($nonCompliantAccounts.Count -eq 0) {
$IsCompliant = $true
$commentsArray = $msgTable.isCompliant + " " + $msgTable.storageAccValidTLS
$commentsArray = @($msgTable.isCompliant, $msgTable.storageAccValidTLS)
}
else{
# Condition: isTLSLessThan1_2 = true if the TLSversionNumeric < 1.2
$filteredPSObjectList | ForEach-Object {
$_ | Add-Member -MemberType NoteProperty -Name isTLSLessThan1_2 -Value ($_.TLSversionNumeric -lt 1.2)
}

$storageAccWithTLSLessThan1_2 = $filteredPSObjectList | Where-Object { $_.IsTLSLessThan1_2 -eq $true }

# condition: storage accounts are all using TLS version 1.2 or higher
if ($storageAccWithTLSLessThan1_2.Count -eq 0){
$IsCompliant = $true
$commentsArray = $msgTable.isCompliant + " " + $msgTable.storageAccValidTLS
}
else{
## keep a record for non-compliant storage acc names for reference
$nonCompliantstorageAccountNames = ($storageAccWithTLSLessThan1_2 | Select-Object -ExpandProperty StorageAccountName | ForEach-Object { $_ } ) -join ', '
Write-Host "Storage accounts which are using TLS1.1 or less: $nonCompliantstorageAccountNames"
$IsCompliant = $false
$commentsArray = $msgTable.isNotCompliant + " " + $msgTable.storageAccNotValidTLS
}
else {
$IsCompliant = $false
$nonCompliantStorageAccountNames = ($nonCompliantAccounts |
Select-Object -ExpandProperty StorageAccountName) -join ', '
Write-Verbose "Storage accounts which are using TLS1.1 or less: $nonCompliantStorageAccountNames"
$commentsArray = @($msgTable.isNotCompliant, $msgTable.storageAccNotValidTLS)
}
}
catch{
$Errorlist.Add("Error creating compliance result: $_")
throw "Error: $_"
catch {
$errorMsg = "Error creating compliance result: $_"
$ErrorList.Add($errorMsg) | Out-Null
Write-Warning $errorMsg
return $moduleOutput
}


$Comments = $commentsArray -join ";"
$Comments = $commentsArray -join " "

$PsObject = [PSCustomObject]@{
ComplianceStatus = $IsCompliant
ControlName = $ControlName
ItemName = $ItemName
Comments = $Comments
ReportTime = $ReportTime
itsgcode = $itsgcode
ReportTime = $ReportTime
itsgcode = $itsgcode
}

# Conditionally add the Profile field based on the feature flag
if ($EnableMultiCloudProfiles) {
$evalResult = Get-EvaluationProfile -CloudUsageProfiles $CloudUsageProfiles -ModuleProfiles $ModuleProfiles
if (!$evalResult.ShouldEvaluate) {
Expand All @@ -131,19 +154,16 @@ function Verify-TLSForStorageAccount {
$PsObject | Add-Member -MemberType NoteProperty -Name "Profile" -Value $evalResult.Profile
$PsObject.Comments = "Not evaluated - Profile $($evalResult.Profile) not present in CloudUsageProfiles"
} else {
$ErrorList.Add("Error occurred while evaluating profile configuration")
$ErrorList.Add("Error occurred while evaluating profile configuration") | Out-Null
}
} else {

$PsObject | Add-Member -MemberType NoteProperty -Name "Profile" -Value $evalResult.Profile
}
}

$moduleOutput = [PSCustomObject]@{
ComplianceResults = $PsObject
Errors = $ErrorList
AdditionalResults = $AdditionalResults
}
$moduleOutput.ComplianceResults = $PsObject
$moduleOutput.Errors = $ErrorList
$moduleOutput.AdditionalResults = $AdditionalResults

return $moduleOutput
}
Expand Down
Loading