Framework/Core/SVT/AzSKCfg/AzSKCfg.ps1
Set-StrictMode -Version Latest class AzSKCfg: SVTBase { AzSKCfg([string] $subscriptionId,[SVTResource] $svtResource): Base($subscriptionId, $svtResource ) { } hidden [ControlResult] CheckifCAPresent([ControlResult] $controlResult) { $AutomationAccount=[Constants]::AutomationAccount $AzSKRGName=[ConfigurationManager]::GetAzSKConfigData().AzSKRGName $caAutomationAccount = Get-AzureRmAutomationAccount -Name $AutomationAccount -ResourceGroupName $AzSKRGName -ErrorAction SilentlyContinue if($caAutomationAccount) { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("CA account '$($AutomationAccount)' is present in the subscription.")); } else { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("CA account '$($AutomationAccount)' is not present in the subscription.")); } return $controlResult } hidden [ControlResult] CheckHealthofCA([ControlResult] $controlResult) { $HasGraphAPIAccess = [RoleAssignmentHelper]::HasGraphAccess(); $AutomationAccount=[Constants]::AutomationAccount $AzSKRGName=[ConfigurationManager]::GetAzSKConfigData().AzSKRGName $AzSKRG = Get-AzureRmResourceGroup -Name $AzSKRGName -ErrorAction SilentlyContinue $stepCount = 0; $caAutomationAccount = Get-AzureRmAutomationAccount -Name $AutomationAccount -ResourceGroupName $AzSKRGName -ErrorAction SilentlyContinue if($caAutomationAccount) { if($HasGraphAPIAccess) { $caInstalledTimeInterval = ($(get-date).ToUniversalTime() - $caAutomationAccount.CreationTime.UtcDateTime).TotalMinutes if($caInstalledTimeInterval -lt 120) { $controlResult.AddMessage([VerificationResult]::Verify, [MessageData]::new("CA account needs minimum 2 hrs to set up.")); return $controlResult } else{ #region: runbook version check $stepCount++ $azskMinReqdRunbookVersion = [ConfigurationManager]::GetAzSKConfigData().AzSKCAMinReqdRunbookVersion $azskLatestCARunbookVersion = [ConfigurationManager]::GetAzSKConfigData().AzSKCARunbookVersion $azskCurrentCARunbookVersion = "" $RunbookVersionTagName="AzSKCARunbookVersion" if($null -ne $AzSKRG) { if(($AzSKRG.Tags | Measure-Object).Count -gt 0 -and $AzSKRG.Tags.ContainsKey($RunbookVersionTagName)) { $azskCurrentCARunbookVersion = $AzSKRG.Tags[$RunbookVersionTagName] } } if(![string]::IsNullOrWhiteSpace($azskCurrentCARunbookVersion) -and ([System.Version]$azskCurrentCARunbookVersion -ge [System.Version]$azskMinReqdRunbookVersion)) { if([System.Version]$azskCurrentCARunbookVersion -ne [System.Version]$azskLatestCARunbookVersion) { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("$($stepCount.ToString("00")):CA runbook is not current as per the required latest version. AzSK current runbook version is $([System.Version]$azskCurrentCARunbookVersion) and latest runbook version is $([System.Version]$azskLatestCARunbookVersion).")); return $controlResult } else { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("$($stepCount.ToString("00")): CA runbook is current as per the required latest version. AzSK current runbook version is $([System.Version]$azskCurrentCARunbookVersion).")); } } else { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("$($stepCount.ToString("00")): CA Runbook is too old.")); return $controlResult } #endregion #region: active schedule $stepCount++ $RunbookName=[Constants]::RunbookName $activeSchedules = $this.GetActiveSchedules($RunbookName) if(($activeSchedules|Measure-Object).Count -eq 0) { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("$($stepCount.ToString("00")): Runbook $($RunbookName) is not scheduled.")); return $controlResult } else { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("$($stepCount.ToString("00")): Active job schedule(s) found.")); } #endregion #region: Check if last job is not successful or job hasn't run in last 2 days $stepCount++ $lastJob = Get-AzureRmAutomationJob -ResourceGroupName $AzSKRGName ` -AutomationAccountName $AutomationAccount ` -RunbookName $RunbookName | Sort-Object LastModifiedTime -Descending | Select-Object -First 1 if(($lastJob |Measure-Object).Count -gt 0) { if(($(get-date).ToUniversalTime() - $lastJob.LastModifiedTime.UtcDateTime).TotalHours -gt 48) { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("$($stepCount.ToString("00")): The CA scanning automation runbook (job) has not run in the last 48 hours.")); return $controlResult } else { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("$($stepCount.ToString("00")): The CA scanning automation runbook (job) is running successfully.")); } } else { $controlResult.AddMessage([VerificationResult]::Verify, [MessageData]::new("$($stepCount.ToString("00")): Job history not found.")); return $controlResult } #endregion #region: Check if service principal is configured and it has at least reader access to subscription and contributor access to "AzSKRG", if either is missing display error message $stepCount++ $isPassed = $false $runAsConnection = $this.GetRunAsConnection() if($runAsConnection) { $CAAADApplicationID = $runAsConnection.FieldDefinitionValues.ApplicationId $spObject = Get-AzureRmADServicePrincipal -ServicePrincipalName $CAAADApplicationID -ErrorAction SilentlyContinue $spName="" if($spObject){$spName = $spObject.DisplayName} $haveSubscriptionRBACAccess = $true; $haveRGRBACAccess = $true; $subRBACoutputs = @(); $haveSubscriptionRBACAccess = $this.CheckServicePrincipalSubscriptionAccess($CAAADApplicationID) $haveRGRBACAccess = $this.CheckServicePrincipalRGAccess($CAAADApplicationID) if($haveSubscriptionRBACAccess -and $haveRGRBACAccess) { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("$($stepCount.ToString("00")): RunAs Account is correctly set up.")); $isPassed = $true } if(!$isPassed) { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("$($stepCount.ToString("00")): Service principal account (Name: $($spName)) configured in RunAs Account doesn't have required access (Reader access on Subscription and/or Contributor access on Resource group AzSKRG)..")); return $controlResult } } else { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("$($stepCount.ToString("00")): RunAs Account does not exist in automation account.")); return $controlResult } #endregion #region:Check if certificate expiry is in near future(in next 1 month) or it's expired $stepCount++ $certificateAssetName = "AzureRunAsCertificate" $runAsCertificate = Get-AzureRmAutomationCertificate -AutomationAccountName $AutomationAccount ` -Name $certificateAssetName ` -ResourceGroupName $AzSKRGName -ErrorAction SilentlyContinue if($runAsCertificate) { $runAsConnection = $this.GetRunAsConnection(); $ADapp = Get-AzureRmADApplication -ApplicationId $runAsConnection.FieldDefinitionValues.ApplicationId -ErrorAction SilentlyContinue if(($runAsCertificate.ExpiryTime.UtcDateTime - $(get-date).ToUniversalTime()).TotalSeconds -lt 0) { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("$($stepCount.ToString("00")): RunAs Certificate is expired on $($runAsCertificate.ExpiryTime).")); return $controlResult } elseif(($runAsCertificate.ExpiryTime - $(get-date)).TotalDays -gt 0 -and ($runAsCertificate.ExpiryTime - $(get-date)).TotalDays -le 30) { $controlResult.AddMessage([VerificationResult]::Verify, [MessageData]::new("$($stepCount.ToString("00")): RunAs Certificate is going to expire within next 30 days. Expiry date: $($runAsCertificate.ExpiryTime).")); return $controlResult } else { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("$($stepCount.ToString("00")): RunAs Certificate is correctly set up.")); } } else { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("$($stepCount.ToString("00")): RunAs Certificate does not exist in automation account.")); return $controlResult } #endregion } } else { $controlResult.CurrentSessionContext.Permissions.HasRequiredAccess = $false; $controlResult.AddMessage([VerificationResult]::Manual, "Not able to query Graph API. This has to be manually verified."); } } else { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("CA account '$($AutomationAccount)' is not present in the subscription.")); } return $controlResult } hidden [ControlResult] CheckifLatestModulePresent([ControlResult] $controlResult) { $AzSKModuleName= [Constants]::AzSKModuleName $currentModuleVersion= [Constants]::AzSKCurrentModuleVersion $serverVersion = [System.Version] ([ConfigurationManager]::GetAzSKConfigData().GetLatestAzSKVersion($AzSKModuleName)); if($currentModuleVersion -ne $serverVersion) { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("Latest AzSK module v.'$($serverVersion)' is not present. The version currently present is '$($currentModuleVersion)'")); } else { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("Latest '$($AzSKModuleName)' module v.'$($currentModuleVersion)' is present")); } return $controlResult } #Check if active schedules hidden [PSObject] GetActiveSchedules($runbookName) { $AutomationAccount=[Constants]::AutomationAccount $AzSKRGName=[ConfigurationManager]::GetAzSKConfigData().AzSKRGName $ScheduleName=[Constants]::ScheduleName $runbookSchedulesList = Get-AzureRmAutomationScheduledRunbook -ResourceGroupName $AzSKRGName ` -AutomationAccountName $AutomationAccount ` -RunbookName $runbookName -ErrorAction Stop if($runbookSchedulesList) { $schedules = Get-AzureRmAutomationSchedule -ResourceGroupName $AzSKRGName ` -AutomationAccountName $AutomationAccount -Name $ScheduleName | Where-Object{ $_.Name -eq $ScheduleName} $activeSchedule = $schedules | Where-Object{$_.IsEnabled -and ` $_.Frequency -ne [Microsoft.Azure.Commands.Automation.Model.ScheduleFrequency]::Onetime -and ` $_.ExpiryTime.UtcDateTime -gt $(get-date).ToUniversalTime()} return $activeSchedule } else { return $null } } hidden [PSObject] GetRunAsConnection() { $AutomationAccount=[Constants]::AutomationAccount $AzSKRGName=[ConfigurationManager]::GetAzSKConfigData().AzSKRGName $connectionAssetName=[Constants]::connectionAssetName $connection = Get-AzureRmAutomationConnection -AutomationAccountName $AutomationAccount ` -Name $connectionAssetName -ResourceGroupName ` $AzSKRGName -ErrorAction SilentlyContinue if((Get-Member -InputObject $connection -Name FieldDefinitionValues -MemberType Properties) -and $connection.FieldDefinitionValues.ContainsKey("ApplicationId")) { $connection = $connection|Select-Object Name,Description,ConnectionTypeName,FieldDefinitionValues return $connection } else { return $null } } hidden [bool] CheckServicePrincipalRGAccess($applicationId) { $AzSKRGName=[ConfigurationManager]::GetAzSKConfigData().AzSKRGName $spPermissions = Get-AzureRmRoleAssignment -serviceprincipalname $applicationId #Check subscription access if(($spPermissions|Measure-Object).count -gt 0) { $haveRGAccess = ($spPermissions | Where-Object {$_.scope -eq (Get-AzureRmResourceGroup -Name $AzSKRGName).ResourceId -and $_.RoleDefinitionName -eq "Contributor"}|measure-object).count -gt 0 return $haveRGAccess } else { return $false } } hidden [bool] CheckServicePrincipalSubscriptionAccess($applicationId) { #fetch SP permissions $spPermissions = Get-AzureRmRoleAssignment -serviceprincipalname $applicationId $currentContext = Get-AzureRMContext #Check subscription access if(($spPermissions|measure-object).count -gt 0) { $haveSubscriptionAccess = ($spPermissions | Where-Object {$_.scope -eq "/subscriptions/$($currentContext.Subscription.Id)" -and $_.RoleDefinitionName -eq "Reader"}|Measure-Object).count -gt 0 return $haveSubscriptionAccess } else { return $false } } } |