Skip to content

Commit

Permalink
[BugFix] - Suspended Main Runbooks and Missing GR13 Compliance Results (
Browse files Browse the repository at this point in the history
#392)

* update

* update

* update

* update

* upgrade az accounts

* update

* update

* update

* update

* update

* update

* update

* update

* update module

* update
  • Loading branch information
singhgss authored Feb 10, 2025
1 parent 28d18e0 commit f253c2f
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 107 deletions.
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

0 comments on commit f253c2f

Please sign in to comment.