diff --git a/.azuredevops/pipelines/AzGovViz.variables.yml b/.azuredevops/pipelines/AzGovViz.variables.yml index 66798ddc..b5cdddc0 100644 --- a/.azuredevops/pipelines/AzGovViz.variables.yml +++ b/.azuredevops/pipelines/AzGovViz.variables.yml @@ -1,4 +1,4 @@ -# AzGovViz v6_major_20220927_1 +# AzGovViz v6_major_20220930_1 # First things first: # 1. Replace with the name of your service connection # 2. Replace with the your ManagementGroupId @@ -56,10 +56,10 @@ variables: # String | example: value: 'azure-ado-serviceconnection' value: '' - # The Management Group ID for the script to start processing with + # The Management Group ID for the script to process - name: ManagementGroupId - # String | example: value: 'MyManagementGroup' - value: '' + # String | example: value: 'MyManagementGroupId' + value: '' #provide the Management Group Id, not the displayName ### Default Variables - Modify as Needed @@ -309,6 +309,11 @@ variables: # Switch | example: value: true value: +# Do not execute Storage Account Access Analysis + - name: NoStorageAccountAccessAnalysis + # Switch | example: value: true + value: + # Dynamic Variables - Do Not Modify Anything Below this line! - name: ExcludedResourceTypesDiagnosticsCapable value: ${{ join(',',parameters.ExcludedResourceTypesDiagnosticsCapableParameters) }} diff --git a/.github/workflows/AzGovViz.yml b/.github/workflows/AzGovViz.yml index c34bb536..51717dfd 100644 --- a/.github/workflows/AzGovViz.yml +++ b/.github/workflows/AzGovViz.yml @@ -1,14 +1,14 @@ -# AzGovViz v6_major_20220912_1 +# AzGovViz v6_major_20220930_1 # First things first: -# 1. Mandatory: define in line 11 (e.g. be992f89-5615-4745-baca-16e5d7b72a50) -# 2. Optional: enable the schedule (line 22,23) +# 1. Mandatory: define in line 11 +# 2. Optional: enable the schedule (line 21,22) # Documentation: https://github.com/JulianHayward/Azure-MG-Sub-Governance-Reporting name: AzGovViz env: OutputPath: wiki - ManagementGroupId: + ManagementGroupId: #provide the Management Group Id, not the displayName ScriptDir: pwsh #example: 'my folder\pwsh' or 'my folder/pwsh' ScriptPrereqFile: prerequisites.ps1 ScriptFile: AzGovVizParallel.ps1 @@ -38,6 +38,7 @@ jobs: with: creds: ${{secrets.CREDS}} enable-AzPSSession: true + # Create secret CREDS (GitHub/Setting/Secrets) # CREDS looks like this: # { # "tenantId": "", diff --git a/.github/workflows/AzGovViz_OIDC.yml b/.github/workflows/AzGovViz_OIDC.yml index e10198c1..9ed131b9 100644 --- a/.github/workflows/AzGovViz_OIDC.yml +++ b/.github/workflows/AzGovViz_OIDC.yml @@ -1,6 +1,6 @@ -# AzGovViz v6_major_20220928_1 +# AzGovViz v6_major_20220930_1 # First things first: -# 1. Mandatory: define in line 11 (e.g. be992f89-5615-4745-baca-16e5d7b72a50) +# 1. Mandatory: define in line 11 # 2. Optional: enable the schedule (line 22,23) # Documentation: https://github.com/JulianHayward/Azure-MG-Sub-Governance-Reporting @@ -8,7 +8,7 @@ name: AzGovViz_OIDC env: OutputPath: wiki - ManagementGroupId: + ManagementGroupId: #provide the Management Group Id, not the displayName ScriptDir: pwsh #example: 'my folder\pwsh' or 'my folder/pwsh' ScriptPrereqFile: prerequisites.ps1 ScriptFile: AzGovVizParallel.ps1 @@ -57,7 +57,7 @@ jobs: uses: azure/powershell@v1 with: inlineScript: | - . .\$($env:ScriptDir)\$($env:ScriptFile) -ManagementGroupId ${env:ManagementGroupId} -SubscriptionId4AzContext ${{secrets.SUBSCRIPTION_ID}} -ScriptPath ${env:ScriptDir} -OutputPath ${env:OutputPath} + . .\$($env:ScriptDir)\$($env:ScriptFile) -ManagementGroupId ${env:ManagementGroupId} -SubscriptionId4AzContext ${{secrets.SUBSCRIPTION_ID}} -ScriptPath ${env:ScriptDir} -OutputPath ${env:OutputPath} -GitHubActionsOIDC azPSVersion: "latest" - name: Push AzGovViz output to repository @@ -74,7 +74,7 @@ jobs: if: env.WebAppPublish == 'true' uses: azure/login@v1 with: - client-id: ${{secrets.CLIENT_ID}} #create this secret + client-id: ${{secrets.CLIENT_ID}} #create this secret (GitHub/Setting/Secrets) tenant-id: ${{secrets.TENANT_ID}} #create this secret subscription-id: ${{secrets.SUBSCRIPTION_ID}} #create this secret enable-AzPSSession: true diff --git a/README.md b/README.md index 0991b314..6d01024a 100644 --- a/README.md +++ b/README.md @@ -59,17 +59,17 @@ Listed as [security monitoring tool](https://docs.microsoft.com/en-us/azure/arch ## Release history -__Changes__ (2022-Sep-28 / Major) - -* New feature 'Storage Account Access Analysis' - provides insights on Storage Accounts with focus on anonymous access (containers/blobs and 'Static website' feature). Data is provided in the HTML __TenantSummary__ (Subscriptions, Resources & Defender) and as CSV export - * New parameter `-NoStorageAccountAccessAnalysis` - do not execute the feature - * New parameter `-StorageAccountAccessAnalysisSubscriptionTags` - define the Subscription tags that should be added to the CSV output - * New parameter `-StorageAccountAccessAnalysisStorageAccountTags` - define the Storage Account (resource) tags that should be added to the CSV output - * Updated `.azuredevops/pipelines/AzGovViz.variables.yml` accordingly -* Rename 'ALZ EverGreen' feature to 'Azure Landing Zones (ALZ) Policy Version Checker' - * Replaced parameter ~~`-NoALZEverGreen`~~ with `-NoALZPolicyVersionChecker` -* Use [AzAPICall](https://aka.ms/AzAPICall) PowerShell module version 1.1.24 -* Optimizations +__Changes__ (2022-Sep-30 / Major) + +* Fix issue #135 + * Embedded GitHub Actions OIDC (Open ID Connect) specific functionality to reconnect and get new token ([AzAPICall](https://aka.ms/AzAPICall)) + * New parameter `-GitHubActionsOIDC` which is only to be used for GitHub Actions `/.github/workflows/AzGovViz_OIDC.yml` + * Updated `/.github/workflows/AzGovViz_OIDC.yml` to use the new parameter `-GitHubActionsOIDC` +* Fix issue #136 + * Handle return for Storage Accounts located in managed Resource Groups + 🌸 Call for contribution: Please review the list of known [managed Resource Groups](https://github.com/JulianHayward/AzSchnitzels/blob/main/info/managedResourceGroups.txt) and contribute if you can, thanks! +* Added missing variable `NoStorageAccountAccessAnalysis` in `.azuredevops/pipelines/AzGovViz.variables.yml` +* Use [AzAPICall](https://aka.ms/AzAPICall) PowerShell module version 1.1.29 Passed tests: Powershell Core 7.2.6 on Windows Passed tests: Powershell Core 7.2.6 Azure DevOps hosted agent ubuntu-20.04 diff --git a/history.md b/history.md index 4079a19d..5b558ffa 100644 --- a/history.md +++ b/history.md @@ -4,6 +4,18 @@ ### AzGovViz version 6 +__Changes__ (2022-Sep-30 / Major) + +* Fix issue #135 + * Embedded GitHub Actions OIDC (Open ID Connect) specific functionality to reconnect and get new token ([AzAPICall](https://aka.ms/AzAPICall)) + * New parameter `-GitHubActionsOIDC` which is only to be used for GitHub Actions `/.github/workflows/AzGovViz_OIDC.yml` + * Updated `/.github/workflows/AzGovViz_OIDC.yml` to use the new parameter `-GitHubActionsOIDC` +* Fix issue #136 + * Handle return for Storage Accounts located in managed Resource Groups + 🌸 Call for contribution: Please review the list of known [managed Resource Groups](https://github.com/JulianHayward/AzSchnitzels/blob/main/info/managedResourceGroups.txt) and contribute if you can, thanks! +* Added missing variable `NoStorageAccountAccessAnalysis` in `.azuredevops/pipelines/AzGovViz.variables.yml` +* Use [AzAPICall](https://aka.ms/AzAPICall) PowerShell module version 1.1.29 + __Changes__ (2022-Sep-28 / Major) * New feature 'Storage Account Access Analysis' - provides insights on Storage Accounts with focus on anonymous access (containers/blobs and 'Static website' feature). Data is provided in the HTML __TenantSummary__ (Subscriptions, Resources & Defender) and as CSV export diff --git a/pwsh/AzGovVizParallel.ps1 b/pwsh/AzGovVizParallel.ps1 index 11daf20e..d79cc690 100644 --- a/pwsh/AzGovVizParallel.ps1 +++ b/pwsh/AzGovVizParallel.ps1 @@ -337,10 +337,10 @@ Param $Product = 'AzGovViz', [string] - $AzAPICallVersion = '1.1.24', + $AzAPICallVersion = '1.1.29', [string] - $ProductVersion = 'v6_major_20220928_1', + $ProductVersion = 'v6_major_20220930_1', [string] $GithubRepository = 'aka.ms/AzGovViz', @@ -521,6 +521,9 @@ Param [array] $StorageAccountAccessAnalysisStorageAccountTags = @('undefined'), + [switch] + $GitHubActionsOIDC, + #https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#role-based-access-control-limits [int] $LimitRBACCustomRoleDefinitionsTenant = 5000, @@ -619,6 +622,7 @@ function addHtParameters { PSRuleFailedOnly = [bool]$PSRuleFailedOnly NoALZPolicyVersionChecker = [bool]$NoALZPolicyVersionChecker NoStorageAccountAccessAnalysis = [bool]$NoStorageAccountAccessAnalysis + GitHubActionsOIDC = [bool]$GitHubActionsOIDC } Write-Host 'htParameters:' $azAPICallConf['htParameters'] | format-table -AutoSize | Out-String @@ -10965,7 +10969,8 @@ function processStorageAccountAnalysis { if ($storageAccountscount -gt 0) { Write-Host " Executing Storage Account Analysis for $storageAccountscount Storage Accounts" $script:arrayStorageAccountAnalysisResults = [System.Collections.ArrayList]::Synchronized((New-Object System.Collections.ArrayList)) - + createBearerToken -AzAPICallConfiguration $azapicallconf -targetEndPoint 'Storage' + $storageAccounts | ForEach-Object -Parallel { $storageAccount = $_ $azAPICallConf = $using:azAPICallConf @@ -10993,25 +10998,31 @@ function processStorageAccountAnalysis { if ($storageAccount.Properties.primaryEndpoints.blob) { $urlServiceProps = "$($storageAccount.Properties.primaryEndpoints.blob)?restype=service&comp=properties" - $saProperties = AzAPICall -AzAPICallConfiguration $azAPICallConf -uri $urlServiceProps -method 'GET' -listenOn 'Content' -currentTask "$($storageAccount.name) get restype=service&comp=properties" - try { - $xmlSaProperties = [xml]([string]$saProperties -replace $saProperties.Substring(0, 3)) - } - catch { - Write-Host "XMLSAPropertiesFailed: Subscription: $($subDetails.displayName) ($subscriptionId) - Storage Account: $($storageAccount.name)" - $saProperties | ConvertTo-Json -Depth 99 + $saProperties = AzAPICall -AzAPICallConfiguration $azAPICallConf -uri $urlServiceProps -method 'GET' -listenOn 'Content' -currentTask "$($storageAccount.name) get restype=service&comp=properties" -saResourceGroupName $resourceGroupName + if ($saProperties -eq 'AuthorizationFailure' -or $saProperties -eq 'AuthorizationPermissionDenied') { + } - - $staticWebsitesState = $false - if ($xmlSaProperties.StorageServiceProperties.StaticWebsite) { - if ($xmlSaProperties.StorageServiceProperties.StaticWebsite.Enabled -eq $true) { - $staticWebsitesState = $true + else { + try { + $xmlSaProperties = [xml]([string]$saProperties -replace $saProperties.Substring(0, 3)) + if ($xmlSaProperties.StorageServiceProperties.StaticWebsite) { + if ($xmlSaProperties.StorageServiceProperties.StaticWebsite.Enabled -eq $true) { + $staticWebsitesState = $true + } + else { + $staticWebsitesState = $false + } + } + } + catch { + Write-Host "XMLSAPropertiesFailed: Subscription: $($subDetails.displayName) ($subscriptionId) - Storage Account: $($storageAccount.name)" + $saProperties | ConvertTo-Json -Depth 99 } } $urlCompList = "$($storageAccount.Properties.primaryEndpoints.blob)?comp=list" $listContainers = AzAPICall -AzAPICallConfiguration $azAPICallConf -uri $urlCompList -method 'GET' -listenOn 'Content' -currentTask "$($storageAccount.name) get comp=list" - if ($listContainers -eq 'AuthorizationFailure') { + if ($listContainers -eq 'AuthorizationFailure' -or $listContainers -eq 'AuthorizationPermissionDenied') { $listContainersSuccess = $false } else { @@ -25509,6 +25520,15 @@ function runInfo { } } + if ($GitHubActionsOIDC) { + Write-Host " GitHubActionsOIDC = $($GitHubActionsOIDC)" -ForegroundColor Green + #$script:paramsUsed += "GitHubActionsOIDC: $($GitHubActionsOIDC) " + } + else { + Write-Host " GitHubActionsOIDC = $($GitHubActionsOIDC)" -ForegroundColor Yellow + #$script:paramsUsed += "GitHubActionsOIDC: $($GitHubActionsOIDC) " + } + } #endregion RunInfo } diff --git a/pwsh/dev/devAzGovVizParallel.ps1 b/pwsh/dev/devAzGovVizParallel.ps1 index 02594e2e..cbbc24d9 100644 --- a/pwsh/dev/devAzGovVizParallel.ps1 +++ b/pwsh/dev/devAzGovVizParallel.ps1 @@ -337,10 +337,10 @@ Param $Product = 'AzGovViz', [string] - $AzAPICallVersion = '1.1.24', + $AzAPICallVersion = '1.1.29', [string] - $ProductVersion = 'v6_major_20220928_1', + $ProductVersion = 'v6_major_20220930_1', [string] $GithubRepository = 'aka.ms/AzGovViz', @@ -521,6 +521,9 @@ Param [array] $StorageAccountAccessAnalysisStorageAccountTags = @('undefined'), + [switch] + $GitHubActionsOIDC, + #https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#role-based-access-control-limits [int] $LimitRBACCustomRoleDefinitionsTenant = 5000, diff --git a/pwsh/dev/functions/addHtParameters.ps1 b/pwsh/dev/functions/addHtParameters.ps1 index c34be509..18676df6 100644 --- a/pwsh/dev/functions/addHtParameters.ps1 +++ b/pwsh/dev/functions/addHtParameters.ps1 @@ -35,6 +35,7 @@ function addHtParameters { PSRuleFailedOnly = [bool]$PSRuleFailedOnly NoALZPolicyVersionChecker = [bool]$NoALZPolicyVersionChecker NoStorageAccountAccessAnalysis = [bool]$NoStorageAccountAccessAnalysis + GitHubActionsOIDC = [bool]$GitHubActionsOIDC } Write-Host 'htParameters:' $azAPICallConf['htParameters'] | format-table -AutoSize | Out-String diff --git a/pwsh/dev/functions/processStorageAccountAnalysis.ps1 b/pwsh/dev/functions/processStorageAccountAnalysis.ps1 index 0e19fe26..9dd692de 100644 --- a/pwsh/dev/functions/processStorageAccountAnalysis.ps1 +++ b/pwsh/dev/functions/processStorageAccountAnalysis.ps1 @@ -5,7 +5,8 @@ function processStorageAccountAnalysis { if ($storageAccountscount -gt 0) { Write-Host " Executing Storage Account Analysis for $storageAccountscount Storage Accounts" $script:arrayStorageAccountAnalysisResults = [System.Collections.ArrayList]::Synchronized((New-Object System.Collections.ArrayList)) - + createBearerToken -AzAPICallConfiguration $azapicallconf -targetEndPoint 'Storage' + $storageAccounts | ForEach-Object -Parallel { $storageAccount = $_ $azAPICallConf = $using:azAPICallConf @@ -33,25 +34,31 @@ function processStorageAccountAnalysis { if ($storageAccount.Properties.primaryEndpoints.blob) { $urlServiceProps = "$($storageAccount.Properties.primaryEndpoints.blob)?restype=service&comp=properties" - $saProperties = AzAPICall -AzAPICallConfiguration $azAPICallConf -uri $urlServiceProps -method 'GET' -listenOn 'Content' -currentTask "$($storageAccount.name) get restype=service&comp=properties" - try { - $xmlSaProperties = [xml]([string]$saProperties -replace $saProperties.Substring(0, 3)) - } - catch { - Write-Host "XMLSAPropertiesFailed: Subscription: $($subDetails.displayName) ($subscriptionId) - Storage Account: $($storageAccount.name)" - $saProperties | ConvertTo-Json -Depth 99 + $saProperties = AzAPICall -AzAPICallConfiguration $azAPICallConf -uri $urlServiceProps -method 'GET' -listenOn 'Content' -currentTask "$($storageAccount.name) get restype=service&comp=properties" -saResourceGroupName $resourceGroupName + if ($saProperties -eq 'AuthorizationFailure' -or $saProperties -eq 'AuthorizationPermissionDenied') { + } - - $staticWebsitesState = $false - if ($xmlSaProperties.StorageServiceProperties.StaticWebsite) { - if ($xmlSaProperties.StorageServiceProperties.StaticWebsite.Enabled -eq $true) { - $staticWebsitesState = $true + else { + try { + $xmlSaProperties = [xml]([string]$saProperties -replace $saProperties.Substring(0, 3)) + if ($xmlSaProperties.StorageServiceProperties.StaticWebsite) { + if ($xmlSaProperties.StorageServiceProperties.StaticWebsite.Enabled -eq $true) { + $staticWebsitesState = $true + } + else { + $staticWebsitesState = $false + } + } + } + catch { + Write-Host "XMLSAPropertiesFailed: Subscription: $($subDetails.displayName) ($subscriptionId) - Storage Account: $($storageAccount.name)" + $saProperties | ConvertTo-Json -Depth 99 } } $urlCompList = "$($storageAccount.Properties.primaryEndpoints.blob)?comp=list" $listContainers = AzAPICall -AzAPICallConfiguration $azAPICallConf -uri $urlCompList -method 'GET' -listenOn 'Content' -currentTask "$($storageAccount.name) get comp=list" - if ($listContainers -eq 'AuthorizationFailure') { + if ($listContainers -eq 'AuthorizationFailure' -or $listContainers -eq 'AuthorizationPermissionDenied') { $listContainersSuccess = $false } else { diff --git a/pwsh/dev/functions/runInfo.ps1 b/pwsh/dev/functions/runInfo.ps1 index 2b457909..48801ee2 100644 --- a/pwsh/dev/functions/runInfo.ps1 +++ b/pwsh/dev/functions/runInfo.ps1 @@ -421,6 +421,15 @@ function runInfo { } } + if ($GitHubActionsOIDC) { + Write-Host " GitHubActionsOIDC = $($GitHubActionsOIDC)" -ForegroundColor Green + #$script:paramsUsed += "GitHubActionsOIDC: $($GitHubActionsOIDC) " + } + else { + Write-Host " GitHubActionsOIDC = $($GitHubActionsOIDC)" -ForegroundColor Yellow + #$script:paramsUsed += "GitHubActionsOIDC: $($GitHubActionsOIDC) " + } + } #endregion RunInfo } \ No newline at end of file diff --git a/version.txt b/version.txt index ff599120..5b984f57 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -v6_major_20220928_1 \ No newline at end of file +v6_major_20220930_1 \ No newline at end of file