From 44873f087779c5ca442cc21ed7f1f0121c1c10ab Mon Sep 17 00:00:00 2001 From: Ali Alvi <137436351+alalvi00@users.noreply.github.com> Date: Fri, 22 Mar 2024 10:09:24 -0400 Subject: [PATCH] Add files via upload --- .github/workflows/deploy_dev_env.yml | 380 +++++++++++++++++++++++++++ 1 file changed, 380 insertions(+) create mode 100644 .github/workflows/deploy_dev_env.yml diff --git a/.github/workflows/deploy_dev_env.yml b/.github/workflows/deploy_dev_env.yml new file mode 100644 index 00000000..3312d89c --- /dev/null +++ b/.github/workflows/deploy_dev_env.yml @@ -0,0 +1,380 @@ +name: Deploy to Dev environment upon Release + +on: + #workflow_run: + # workflows: + # - "Azure CAC Release" + # types: + # - completed + + #This workflow will be triggered by push to main for test purposes + on: + workflow_dispatch: + push: + paths-ignore: + - 'README.md' + - 'SECURITY.md' + - 'SUPPORT.md' + - 'psmodules/**' + - 'docs/**' + branches: + - main + + +permissions: + id-token: write + +env: + ARTIFACT_NAME: PowerShell.Workflows.ScriptSigning + +jobs: + sign-scripts: + name: Validate, test and publish Powershell scripts as pipeline artifacts + runs-on: windows-2019 + environment: dev + steps: + - name: Check out repository + uses: actions/checkout@v2 + - name: Validate Signature + shell: powershell + run: | + $signatureStatuses = Get-ChildItem -r -i *.ps* | Get-AuthenticodeSignature + Foreach ($signatureStatus in $signatureStatuses) { + If ($signatureStatus.Status -eq 'HashMismatch') { + throw "File '$($signatureStatus.Path)' has a hash status of '$($signatureStatus.status)'" + } + ElseIf ($signatureStatus.Status -eq 'NotSigned') { + Write-Warning "File '$($signatureStatus.Path)' has a hash status of '$($signatureStatus.status)'" + } + ElseIf ($signatureStatus.Status -eq 'Valid') { + Write-Host "File '$($signatureStatus.Path)' has a hash status of '$($signatureStatus.status)'" + } + Else { + throw "File '$($signatureStatus.Path)' has an unhandled hash status of '$($signatureStatus.status)'" + } + } + + - name: Test Module Imports + shell: powershell + run: | + $ErrorActionPreference = 'Stop' + $moduleFiles = Get-ChildItem -path ./* -recurse -include *.psm1 + Write-Host "Count of module files: $($moduleFiles.count)" + + try { + ForEach ($moduleFile in $moduleFiles) { + Import-Module $moduleFile.Fullname -ErrorAction Stop + } + } + catch { + throw "Failed test import module '$moduleFile' with error: $_" + } + $importedModules = Get-Module + Write-Host "Imported modules: `n $($importedModules.Path | Out-String)" + $missingModules = $moduleFiles | Where-object {$_ -inotin ($importedModules).Path} + If ($missingModules) { + throw "The following modules failed import test: $missingModules" + } + + - name: Zip Signed Modules + shell: powershell + run: | + $moduleCodeFilesObjs = Get-ChildItem -Path .\src -Recurse -Include *.psm1 -Exclude '*-GSA*','*GuardrailsSolutionAcceleratorSetup*','*Deploy-GuardrailsSolutionAccelerator*' + Write-Host "'$($moduleCodeFilesObjs.count)' module manifest files " + ForEach ($moduleCodeFile in $moduleCodeFilesObjs) { + $moduleManifestFile = Get-Item -Path $moduleCodeFile.FullName.replace('psm1','psd1') + + If ($moduleCodeFilesObjs.FullName -icontains $moduleCodeFile.FullName -or $moduleCodeFilesObjs.FullName -icontains $moduleManifestFile.FullName) { + Write-Host "Module '$($moduleCodeFile.BaseName)' found, zipping module files..." + $destPath = "./psmodules/$($moduleCodeFile.BaseName).zip" + If ($moduleCodeFile.DIrectory.Name -eq 'Guardrails-Localization') { + Compress-Archive -Path "$($moduleCodeFile.Directory)/*" -DestinationPath $destPath -Force + } + Else { + $filesToZip = $moduleManifestFile,$moduleCodeFile + Compress-Archive -Path $filesToZip -DestinationPath $destPath -Force + } + } + Else { + Write-Host "Neither the manifest '$($moduleCodeFile.FullName.toLower())' or script file '$($moduleManifestFile.FullName.ToLower())' for module '$($moduleCodeFile.BaseName)' was changed, skipping zipping..." + } + } + - name: Publish artifacts + uses: actions/upload-artifact@v3 + with: + name: ${{ env.ARTIFACT_NAME }} + path: ./psmodules/*.zip + +deploy: + name: Deploy CaC to Dev Tenant + needs: sign-scripts + runs-on: ubuntu-latest + environment: dev + steps: + - name: Check out + uses: actions/checkout@v3 + - name: Download zipped modules and replace old ones + uses: actions/download-artifact@v3 + with: + name: ${{env.ARTIFACT_NAME}} + path: ./psmodules + - name: AZ Login + uses: azure/login@v1 + with: + client-id: ${{ secrets.DEV_AZURE_CLIENT_ID}} + tenant-id: ${{ secrets.DEV_AZURE_TENANT_ID}} + subscription-id: ${{ secrets.DEV_AZURE_SUBSCRIPTION_ID}} + enable-AzPSSession: true + - name: Stage zipped/signed modules in Storage Account + uses: azure/powershell@v1 + with: + inlineScript: | + Set-AzContext -SubscriptionId $env:SUBSCRIPTIONID + $storageContext = (Get-AzStorageAccount -ResourceGroupName $env:PIPELINEMODULESTAGING_RGNAME -Name $env:PIPELINEMODULESTAGING_STORAGEACCOUNTNAME).Context + $zippedModules = Get-ChildItem -Path ./psmodules/* -Include *.zip -File + ForEach ($moduleZip in $zippedModules) { + Set-AzStorageBlobContent -Context $storageContext -Container psmodules -File $moduleZip.FullName -Blob $moduleZip.Name -Force -ErrorAction Stop + } + azPSVersion: "latest" + env: + PIPELINEMODULESTAGING_RGNAME: ${{ vars.PIPELINEMODULESTAGING_RGNAME }} + PIPELINEMODULESTAGING_STORAGEACCOUNTNAME: ${{ vars.PIPELINEMODULESTAGING_SANAME_DEV }} + SUBSCRIPTIONID: ${{ secrets.DEV_AZURE_SUBSCRIPTION_ID }} + + - name: Pre-Clean Test environment + uses: azure/powershell@v1 + continue-on-error: true + with: + inlineScript: | + Set-AzContext -SubscriptionId $env:DEVSUBSCRIPTION_ID + ipmo ./src/GuardrailsSolutionAcceleratorSetup + $configFilePath = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath 'config.json' + $CBSSUBSCRIPTION_DEV_NAME = $env:CBSSUBSCRIPTION_DEV_NAME + $DEVSUBSCRIPTION_ID = $env:DEVSUBSCRIPTION_ID + $LIGHTHOUSEPROVIDER_TENANTID = $env:LIGHTHOUSEPROVIDER_TENANTID + $LIGHTHOUSEPROVIDER_PRINCIPALID = $env:LIGHTHOUSEPROVIDER_PRINCIPALID + $LIGHTHOUSEPROVIDER_MGMTGRPID_DEV = $env:LIGHTHOUSEPROVIDER_MGMTGRPID_DEV + $UNIQUENAME_SUFFIX_DEV = $env:UNIQUENAME_SUFFIX_DEV + $DEVTENANT_BGA1 = $env:DEVTENANT_BGA1 + $DEVTENANT_BGA2 = $env:DEVTENANT_BGA2 + $PBMMPOLICY_ID = $env:PBMMPOLICY_ID + $LOCATIONPOLICY_ID = $env:LOCATIONPOLICY_ID + $DEVLAW_SEC_HEALTH_SHARED = $env:DEVLAW_SEC_HEALTH_SHARED + $DEVLAW_SEC_HEALTH_SHARED = $env:DEVLAW_SEC_HEALTH_SHARED + + $configContent = @" + { + "keyVaultName": "kv-cac", + "resourcegroup": "rg-cac", + "region": "CanadaCentral", + "storageaccountName": "stac-cac", + "logAnalyticsworkspaceName": "log-cac", + "autoMationAccountName": "aa-cac", + "FirstBreakGlassAccountUPN": "$DEVTENANT_BGA1", + "SecondBreakGlassAccountUPN": "$DEVTENANT_BGA2", + "PBMMPolicyID": "$PBMMPOLICY_ID", + "AllowedLocationPolicyId": "$LOCATIONPOLICY_ID", + "DepartmentNumber": "163", + "CBSSubscriptionName": "$CBSSUBSCRIPTION_DEV_NAME", + "securityLAWResourceId": "$DEVLAW_SEC_HEALTH_SHARED", + "healthLAWResourceId": "$DEVLAW_SEC_HEALTH_SHARED", + "Locale": "en-CA", + "lighthouseServiceProviderTenantID": "$LIGHTHOUSEPROVIDER_TENANTID", + "lighthousePrincipalDisplayName": "GcPc-CTO-Guardrails_Compliance-Owners", + "lighthousePrincipalId": "$LIGHTHOUSEPROVIDER_PRINCIPALID", + "lighthouseTargetManagementGroupID": "$LIGHTHOUSEPROVIDER_MGMTGRPID_DEV", + "subscriptionId": "$DEVSUBSCRIPTION_ID", + "SSCReadOnlyServicePrincipalNameAPPID": "00000000-0000-0000-0000-000000000000", + "uniqueNameSuffix": "$UNIQUENAME_SUFFIX_DEV", + "securityRetentionDays": "730", + "cloudUsageProfiles": "3" + } + "@ + Set-Content -Path $configFilePath -Value $configContent + Push-Location -Path setup + + try { + $ErrorActionPreference = 'Stop' + remove-gsacentralizedReportingCustomerComponents -Force -configFilePath $configFilePath -verbose + Remove-GSACentralizedDefenderCustomerComponents -Force -configFilePath $configFilePath -verbose + Remove-GSACoreResources -Force -Wait -configFilePath $configFilePath -verbose + } + catch { + throw "Failed test deploy of solution with error: $_" + } + finally { + If (!$?) {throw "Failed test deploy of solution with error: $($error[0]) $_"} + Pop-Location + } + azPSVersion: "latest" + env: + DEVTENANT_DOMAIN: ${{ vars.DEVTENANT_DOMAIN }} + DEVSUBSCRIPTION_ID: ${{ vars.DEVSUBSCRIPTION_ID }} + CBSSUBSCRIPTION_DEV_NAME: ${{ vars.CBSSUBSCRIPTION_DEV_NAME }} + LIGHTHOUSEPROVIDER_TENANTID: ${{ vars.LIGHTHOUSEPROVIDER_TENANTID }} + LIGHTHOUSEPROVIDER_PRINCIPALID: ${{ vars.LIGHTHOUSEPROVIDER_PRINCIPALID }} + LIGHTHOUSEPROVIDER_MGMTGRPID_DEV: ${{ vars.LIGHTHOUSEPROVIDER_MGMTGRPID_DEV }} + UNIQUENAME_SUFFIX_DEV: ${{ vars.UNIQUENAME_SUFFIX_DEV }} + DEVTENANT_BGA1: ${{ vars.DEVTENANT_BGA1 }} + DEVTENANT_BGA2: ${{ vars.DEVTENANT_BGA2 }} + PBMMPOLICY_ID: ${{ vars.PBMMPOLICY_ID }} + LOCATIONPOLICY_ID: ${{ vars.LOCATIONPOLICY_ID }} + DEVLAW_SEC_HEALTH_SHARED: ${{ vars.DEVLAW_SEC_HEALTH_SHARED }} + DEVLAW_SEC_HEALTH_SHARED: ${{ vars.DEVLAW_SEC_HEALTH_SHARED }} + - name: Relogin AZ + uses: azure/login@v1 + with: + client-id: ${{ secrets.DEV_AZURE_CLIENT_ID}} + tenant-id: ${{ secrets.DEV_AZURE_TENANT_ID}} + subscription-id: ${{ secrets.DEV_AZURE_SUBSCRIPTION_ID}} + enable-AzPSSession: true + - name: Deploy Test Environment + uses: azure/powershell@v1 + with: + inlineScript: | + Set-AzContext -SubscriptionId $env:DEVSUBSCRIPTION_ID + $configFilePath = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath 'config.json' + $CBSSUBSCRIPTION_DEV_NAME = $env:CBSSUBSCRIPTION_DEV_NAME + $DEVSUBSCRIPTION_ID = $env:DEVSUBSCRIPTION_ID + $LIGHTHOUSEPROVIDER_TENANTID = $env:LIGHTHOUSEPROVIDER_TENANTID + $LIGHTHOUSEPROVIDER_PRINCIPALID = $env:LIGHTHOUSEPROVIDER_PRINCIPALID + $LIGHTHOUSEPROVIDER_MGMTGRPID_DEV = $env:LIGHTHOUSEPROVIDER_MGMTGRPID_DEV + $UNIQUENAME_SUFFIX_DEV = $env:UNIQUENAME_SUFFIX_DEV + $DEVTENANT_BGA1 = $env:DEVTENANT_BGA1 + $DEVTENANT_BGA2 = $env:DEVTENANT_BGA2 + $PBMMPOLICY_ID = $env:PBMMPOLICY_ID + $LOCATIONPOLICY_ID = $env:LOCATIONPOLICY_ID + $DEVLAW_SEC_HEALTH_SHARED = $env:DEVLAW_SEC_HEALTH_SHARED + $DEVLAW_SEC_HEALTH_SHARED = $env:DEVLAW_SEC_HEALTH_SHARED + + $configContent = @" + { + "keyVaultName": "kv-cac", + "resourcegroup": "rg-cac", + "region": "CanadaCentral", + "storageaccountName": "stac-cac", + "logAnalyticsworkspaceName": "log-cac", + "autoMationAccountName": "aa-cac", + "FirstBreakGlassAccountUPN": "$DEVTENANT_BGA1", + "SecondBreakGlassAccountUPN": "$DEVTENANT_BGA2", + "PBMMPolicyID": "$PBMMPOLICY_ID", + "AllowedLocationPolicyId": "$LOCATIONPOLICY_ID", + "DepartmentNumber": "163", + "CBSSubscriptionName": "$CBSSUBSCRIPTION_DEV_NAME", + "securityLAWResourceId": "$DEVLAW_SEC_HEALTH_SHARED", + "healthLAWResourceId": "$DEVLAW_SEC_HEALTH_SHARED", + "Locale": "en-CA", + "lighthouseServiceProviderTenantID": "$LIGHTHOUSEPROVIDER_TENANTID", + "lighthousePrincipalDisplayName": "GcPc-CTO-Guardrails_Compliance-Owners", + "lighthousePrincipalId": "$LIGHTHOUSEPROVIDER_PRINCIPALID", + "lighthouseTargetManagementGroupID": "$LIGHTHOUSEPROVIDER_MGMTGRPID_DEV", + "subscriptionId": "$DEVSUBSCRIPTION_ID", + "SSCReadOnlyServicePrincipalNameAPPID": "00000000-0000-0000-0000-000000000000", + "uniqueNameSuffix": "$UNIQUENAME_SUFFIX_DEV", + "securityRetentionDays": "730", + "cloudUsageProfiles": "3" + } + "@ + Set-Content -Path $configFilePath -Value $configContent + + # Load tags JSON content into a variable + $setupFileRelativePath = "setup/tags.json" + $setupFullPath = Join-Path $env:GITHUB_WORKSPACE $setupFileRelativePath + $jsonContent = Get-Content -Raw -Path $setupFullPath | ConvertFrom-Json + # Add additional tags for dev tenant + $jsonContent | Add-Member -Type NoteProperty -Name 'ClientOrganization' -Value 'SSC' + $jsonContent | Add-Member -Type NoteProperty -Name 'CostCenter' -Value 'SSC Cloud Operations' + $jsonContent | Add-Member -Type NoteProperty -Name 'DataSensitivity' -Value 'PB' + $jsonContent | Add-Member -Type NoteProperty -Name 'ProjectContact' -Value 'Amrinder' + $jsonContent | Add-Member -Type NoteProperty -Name 'ProjectName' -Value 'ComplianceAsCodeAzure' + $jsonContent | Add-Member -Type NoteProperty -Name 'TechnicalContact' -Value 'Amrinder' + # Save the modified content back to the tags JSON file + $jsonContent | ConvertTo-Json | Set-Content -Path $setupFullPath + $storageContext = (Get-AzStorageAccount -ResourceGroupName $env:PIPELINEMODULESTAGING_RGNAME -Name $env:PIPELINEMODULESTAGING_STORAGEACCOUNTNAME).context + $modulesStagingURI = $storageContext.BlobEndpoint.ToString() + 'psmodules' + $alternatePSModulesURL = $modulesStagingURI + Write-Output "alternatePSModulesURL is '$alternatePSModulesURL'" + $optionalParams = @{} + if ($alternatePSModulesURL) { + $optionalParams['alternatePSModulesURL'] = $alternatePSModulesURL + } + try { + $ErrorActionPreference = 'Stop' + ipmo ./src/GuardrailsSolutionAcceleratorSetup + Deploy-GuardrailsSolutionAccelerator -configFilePath $configFilePath -newComponents CoreComponents, CentralizedCustomerDefenderForCloudSupport, CentralizedCustomerReportingSupport -Yes @optionalParams -verbose + } + catch { + throw "Failed test deploy of solution with error: $_" + } + finally { + If (!$?) {throw "Failed test deploy of solution with error: $($error[0]) $_"} + Pop-Location + } + azPSVersion: "latest" + env: + PIPELINEMODULESTAGING_RGNAME: ${{ vars.PIPELINEMODULESTAGING_RGNAME }} + PIPELINEMODULESTAGING_STORAGEACCOUNTNAME: ${{ vars.PIPELINEMODULESTAGING_SANAME_DEV }} + DEVSUBSCRIPTION_ID: ${{ vars.DEVSUBSCRIPTION_ID }} + CBSSUBSCRIPTION_DEV_NAME: ${{ vars.CBSSUBSCRIPTION_DEV_NAME }} + LIGHTHOUSEPROVIDER_TENANTID: ${{ vars.LIGHTHOUSEPROVIDER_TENANTID }} + LIGHTHOUSEPROVIDER_PRINCIPALID: ${{ vars.LIGHTHOUSEPROVIDER_PRINCIPALID }} + LIGHTHOUSEPROVIDER_MGMTGRPID_DEV: ${{ vars.LIGHTHOUSEPROVIDER_MGMTGRPID_DEV }} + UNIQUENAME_SUFFIX_DEV: ${{ vars.UNIQUENAME_SUFFIX_DEV }} + DEVTENANT_BGA1: ${{ vars.DEVTENANT_BGA1 }} + DEVTENANT_BGA2: ${{ vars.DEVTENANT_BGA2 }} + PBMMPOLICY_ID: ${{ vars.PBMMPOLICY_ID }} + LOCATIONPOLICY_ID: ${{ vars.LOCATIONPOLICY_ID }} + DEVLAW_SEC_HEALTH_SHARED: ${{ vars.DEVLAW_SEC_HEALTH_SHARED }} + DEVLAW_SEC_HEALTH_SHARED: ${{ vars.DEVLAW_SEC_HEALTH_SHARED }} + + - name: Check for AA Job Errors + uses: azure/powershell@v1 + with: + inlineScript: | + ipmo ./src/GuardrailsSolutionAcceleratorSetup + $c = Get-GSAExportedConfig -KeyVaultName gsapipe-$env:UNIQUENAME_SUFFIX_DEV -y + $config = $c.configString | ConvertFrom-Json + + Write-Output "Waiting for 'main' and 'backend' runbook jobs to complete (up to 5 mins)" + $timeout = New-TimeSpan -Minutes 5 + $timer = [System.Diagnostics.Stopwatch]::StartNew() + do { + $jobMain = Get-AzAutomationJob -RunbookName 'main' -ResourceGroupName $config.runtime.resourceGroup -AutomationAccountName $config.runtime.automationAccountName | + Sort-Object StartTIme -Descending | + Select-Object -First 1 + + $jobBackend = Get-AzAutomationJob -RunbookName 'backend' -ResourceGroupName $config.runtime.resourceGroup -AutomationAccountName $config.runtime.automationAccountName | + Sort-Object StartTIme -Descending | + Select-Object -First 1 + + Start-Sleep 1 + } + until (($jobMain.Status -in 'Completed','Failed' -and $jobBackend -in 'Completed','Failed') -or ($timer.Elapsed -ge $timeout)) + If ($jobMain.Status -eq 'Failed') { + throw "main runbook failed to execute" + } + If ($jobMain.Status -eq 'Completed') { + Write-Output "'main' runbook completed successfully, checking for errors in output. " + } + If ($jobBackend.Status -eq 'Failed') { + throw "backend runbook failed to execute" + } + If ($jobBackend.Status -eq 'Completed') { + Write-Output "'backend' runbook completed successfully, checking for errors in output. " + } + $jobMainOutput = Get-AzAutomationJobOutput -Id $jobMain.JobId -ResourceGroupName $config.runtime.resourceGroup -AutomationAccountName $config.runtime.automationAccountName -Stream 'Error' + $jobBackendOutput = Get-AzAutomationJobOutput -Id $jobBackend.JobId -ResourceGroupName $config.runtime.resourceGroup -AutomationAccountName $config.runtime.automationAccountName -Stream 'Error' + $errorsFound = $false + ForEach ($outputRecord in $jobMainOutput) { + If ($outputRecord.Summary -like 'Failed invoke the module execution script for module*') { + throw 'Errors found in "main" runbook Azure Automation jobs' + } + } + ForEach ($outputRecord in $jobBackendOutput) { + If ($outputRecord.Summary -like 'Failed invoke the module execution script for module*') { + throw 'Errors found in "backend" runbook Azure Automation jobs' + } + } + azPSVersion: "latest" + env: + UNIQUENAME_SUFFIX_DEV: ${{ vars.UNIQUENAME_SUFFIX_DEV }}