Skip to content

Deploy to Dev environment upon Release #101

Deploy to Dev environment upon Release

Deploy to Dev environment upon Release #101

name: Deploy to Dev environment upon Release
on:
workflow_run:
workflows: [Azure CAC Release]
types:
- completed
concurrency:
group: Deploy-Azure-CAC-Dev
cancel-in-progress: false
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: test
steps:
- name: Check out repository
uses: actions/checkout@v2
- 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@v4
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@v4
with:
name: ${{env.ARTIFACT_NAME}}
path: ./psmodules
- name: AZ Login
uses: azure/login@v2
with:
creds: ${{ secrets.DEV_AZURE_CREDENTIALS }}
enable-AzPSSession: true
- name: Stage zipped/signed modules in Storage Account
uses: azure/powershell@v2
with:
inlineScript: |
Set-AzContext -SubscriptionId $env:DEVSUBSCRIPTION_ID
$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 }}
DEVSUBSCRIPTION_ID: ${{ secrets.DEV_AZURE_SUBSCRIPTION_ID}}
- name: Pre-Clean Dev environment
if: ${{ env.DEV_UPGRADE_VAR != 'true'}}
uses: azure/powershell@v2
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
$INITIATIVELOCATION_ID = $env:INITIATIVELOCATION_ID_DEV
$DEVLAW_SEC = $env:DEVLAW_SEC
$DEVLAW_HEALTH = $env:DEVLAW_HEALTH
$ENABLE_MULTICLOUD_PROFILES = $env:ENABLE_MULTICLOUD_PROFILES
$DEV_UPGRADE_VAR = $env:DEV_UPGRADE_VAR
$configContent = @"
{
"keyVaultName": "kvcac",
"resourcegroup": "guardrailscac",
"region": "CanadaCentral",
"storageaccountName": "stcac",
"logAnalyticsworkspaceName": "logcac",
"autoMationAccountName": "aacac",
"FirstBreakGlassAccountUPN": "$DEVTENANT_BGA1",
"SecondBreakGlassAccountUPN": "$DEVTENANT_BGA2",
"PBMMPolicyID": "$PBMMPOLICY_ID",
"AllowedLocationPolicyId": "$LOCATIONPOLICY_ID",
"AllowedLocationInitiativeId": "$INITIATIVELOCATION_ID",
"DepartmentNumber": "163",
"CBSSubscriptionName": "$CBSSUBSCRIPTION_DEV_NAME",
"securityLAWResourceId": "$DEVLAW_SEC",
"healthLAWResourceId": "$DEVLAW_HEALTH",
"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",
"enableMultiCloudProfiles": "$ENABLE_MULTICLOUD_PROFILES"
}
"@
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 }}
INITIATIVELOCATION_ID_DEV: ${{ vars.INITIATIVELOCATION_ID_DEV}}
DEVLAW_SEC: ${{ vars.DEVLAW_SEC }}
DEVLAW_HEALTH: ${{ vars.DEVLAW_HEALTH }}
DEV_UPGRADE_VAR: ${{ vars.DEV_UPGRADE_VAR}}
ENABLE_MULTICLOUD_PROFILES: ${{ vars.DEV_ENABLE_MULTICLOUD_PROFILE }}
# - name: Relogin AZ
# uses: azure/login@v2
# 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 Dev Environment
uses: azure/powershell@v2
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
$INITIATIVELOCATION_ID = $env:INITIATIVELOCATION_ID_DEV
$DEVLAW_SEC = $env:DEVLAW_SEC
$DEVLAW_HEALTH = $env:DEVLAW_HEALTH
$ENABLE_MULTICLOUD_PROFILES = $env:ENABLE_MULTICLOUD_PROFILES
$DEV_UPGRADE_VAR = $env:DEV_UPGRADE_VAR
$configContent = @"
{
"keyVaultName": "kvcac",
"resourcegroup": "guardrailscac",
"region": "CanadaCentral",
"storageaccountName": "stcac",
"logAnalyticsworkspaceName": "logcac",
"autoMationAccountName": "aacac",
"FirstBreakGlassAccountUPN": "$DEVTENANT_BGA1",
"SecondBreakGlassAccountUPN": "$DEVTENANT_BGA2",
"PBMMPolicyID": "$PBMMPOLICY_ID",
"AllowedLocationPolicyId": "$LOCATIONPOLICY_ID",
"AllowedLocationInitiativeId": "$INITIATIVELOCATION_ID",
"DepartmentNumber": "163",
"CBSSubscriptionName": "$CBSSUBSCRIPTION_DEV_NAME",
"securityLAWResourceId": "$DEVLAW_SEC",
"healthLAWResourceId": "$DEVLAW_HEALTH",
"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",
"enableMultiCloudProfiles": "$ENABLE_MULTICLOUD_PROFILES"
}
"@
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
if ($DEV_UPGRADE_VAR -eq "true"){
Write-Output "Upgrade workflow flag is set to '$DEV_UPGRADE_VAR'"
Write-Output "Upgrading the CaC solution"
Deploy-GuardrailsSolutionAccelerator -configFilePath $configFilePath -update -Yes @optionalParams -verbose
}
else {
Write-Output "Upgrade workflow flag is set to '$DEV_UPGRADE_VAR'"
Write-Output "Deploying a new installation of the CaC solution"
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 }}
INITIATIVELOCATION_ID_DEV: ${{ vars.INITIATIVELOCATION_ID_DEV}}
DEVLAW_SEC: ${{ vars.DEVLAW_SEC }}
DEVLAW_HEALTH: ${{ vars.DEVLAW_HEALTH }}
DEV_UPGRADE_VAR: ${{ vars.DEV_UPGRADE_VAR}}
ENABLE_MULTICLOUD_PROFILES: ${{ vars.DEV_ENABLE_MULTICLOUD_PROFILE }}
- name: Check for AA Job Errors
uses: azure/powershell@v2
with:
inlineScript: |
ipmo ./src/GuardrailsSolutionAcceleratorSetup
$c = Get-GSAExportedConfig -KeyVaultName kvcac-$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 }}