Framework/Helpers/OMSHelper.ps1
Set-StrictMode -Version Latest Class OMSHelper{ static [string] $DefaultOMSType = "AzSK" # Create the function to create and post the request static PostOMSData([string] $OMSWorkspaceID, [string] $SharedKey, $Body, $LogType) { if([string]::IsNullOrWhiteSpace($LogType)) { $LogType = [OMSHelper]::DefaultOMSType } [string] $method = "POST" [string] $contentType = "application/json" [string] $resource = "/api/logs" $rfc1123date = [System.DateTime]::UtcNow.ToString("r") [int] $contentLength = $Body.Length [string] $signature = [OMSHelper]::GetOMSSignature($OMSWorkspaceID , $SharedKey , $rfc1123date ,$contentLength ,$method ,$contentType ,$resource) [string] $uri = "https://" + $OMSWorkspaceID + ".ods.opinsights.azure.com" + $resource + "?api-version=2016-04-01" [DateTime] $TimeStampField = [System.DateTime]::UtcNow $headers = @{ "Authorization" = $signature; "Log-Type" = $LogType; "x-ms-date" = $rfc1123date; "time-generated-field" = $TimeStampField; } $response = Invoke-WebRequest -Uri $uri -Method $method -ContentType $contentType -Headers $headers -Body $Body -UseBasicParsing } static [string] GetOMSSignature ($OMSWorkspaceID, $SharedKey, $Date, $ContentLength, $Method, $ContentType, $Resource) { [string] $xHeaders = "x-ms-date:" + $Date [string] $stringToHash = $Method + "`n" + $ContentLength + "`n" + $ContentType + "`n" + $xHeaders + "`n" + $Resource [byte[]]$bytesToHash = [Text.Encoding]::UTF8.GetBytes($stringToHash) [byte[]]$keyBytes = [Convert]::FromBase64String($SharedKey) [System.Security.Cryptography.HMACSHA256] $sha256 = New-Object System.Security.Cryptography.HMACSHA256 $sha256.Key = $keyBytes [byte[]]$calculatedHash = $sha256.ComputeHash($bytesToHash) $encodedHash = [Convert]::ToBase64String($calculatedHash) $authorization = 'SharedKey {0}:{1}' -f $OMSWorkspaceID,$encodedHash return $authorization } static [PSObject[]] GetOMSBodyObjects([SVTEventContext] $eventContext,[AzSKContextDetails] $AzSKContext) { [PSObject[]] $output = @(); [array] $eventContext.ControlResults | ForEach-Object{ Set-Variable -Name ControlResult -Value $_ -Scope Local $out = [OMSModel]::new() if($eventContext.IsResource()) { $out.ResourceType=$eventContext.ResourceContext.ResourceType $out.ResourceGroup=$eventContext.ResourceContext.ResourceGroupName $out.ResourceName=$eventContext.ResourceContext.ResourceName $out.ResourceId = $eventContext.ResourceContext.ResourceId $out.ChildResourceName=$ControlResult.ChildResourceName } $out.Reference=$eventContext.Metadata.Reference $out.ControlStatus=$ControlResult.VerificationResult.ToString() $out.ActualVerificationResult=$ControlResult.ActualVerificationResult.ToString() $out.ControlId=$eventContext.ControlItem.ControlID $out.SubscriptionName=$eventContext.SubscriptionContext.SubscriptionName $out.SubscriptionId=$eventContext.SubscriptionContext.SubscriptionId $out.FeatureName=$eventContext.FeatureName $out.Recommendation=$eventContext.ControlItem.Recommendation $out.ControlSeverity=$eventContext.ControlItem.ControlSeverity.ToString() $out.Source=$AzSKContext.Source $out.Tags=$eventContext.ControlItem.Tags $out.RunIdentifier = $AzSKContext.RunIdentifier $out.HasRequiredAccess = $ControlResult.CurrentSessionContext.Permissions.HasRequiredAccess $out.ScannerVersion = $AzSKContext.Version $out.IsBaselineControl = $eventContext.ControlItem.IsBaselineControl $out.HasAttestationWritePermissions = $ControlResult.CurrentSessionContext.Permissions.HasAttestationWritePermissions $out.HasAttestationReadPermissions = $ControlResult.CurrentSessionContext.Permissions.HasAttestationReadPermissions $out.IsLatestPSModule = $ControlResult.CurrentSessionContext.IsLatestPSModule #mapping the attestation properties if($null -ne $ControlResult -and $null -ne $ControlResult.StateManagement -and $null -ne $ControlResult.StateManagement.AttestedStateData) { $attestedData = $ControlResult.StateManagement.AttestedStateData; $out.AttestationStatus = $ControlResult.AttestationStatus.ToString(); $out.AttestedBy = $attestedData.AttestedBy; $out.Justification = $attestedData.Justification; $out.AttestedDate = $attestedData.AttestedDate $out.ExpiryDate = $attestedData.ExpiryDate } $output += $out } return $output } static [void] PostApplicableControlSet([SVTEventContext[]] $contexts,[AzSKContextDetails] $AzSKContext) { if (($contexts | Measure-Object).Count -lt 1) { return; } $set = [OMSHelper]::ConvertToSimpleSet($contexts,$AzSKContext); [OMSHelper]::WriteControlResult($set,"AzSK_Inventory") $omsMetadata = [ConfigurationManager]::LoadServerConfigFile("OMSSettings.json") [OMSHelper]::WriteControlResult($omsMetadata,"AzSK_MetaData") } static [void] WriteControlResult([PSObject[]] $omsDataObject, [string] $OMSEventType) { try { $settings = [ConfigurationManager]::GetAzSKSettings() if([string]::IsNullOrWhiteSpace($OMSEventType)) { $OMSEventType = $settings.OMSType } if((-not [string]::IsNullOrWhiteSpace($settings.OMSWorkspaceId)) -or (-not [string]::IsNullOrWhiteSpace($settings.AltOMSWorkspaceId))) { $omsDataObject | ForEach-Object{ Set-Variable -Name tempBody -Value $_ -Scope Local $body = $tempBody | ConvertTo-Json $omsBodyByteArray = ([System.Text.Encoding]::UTF8.GetBytes($body)) #publish to primary workspace if(-not [string]::IsNullOrWhiteSpace($settings.OMSWorkspaceId)) { [OMSHelper]::PostOMSData($settings.OMSWorkspaceId, $settings.OMSSharedKey, $omsBodyByteArray, $OMSEventType) } #publish to secondary workspace if(-not [string]::IsNullOrWhiteSpace($settings.AltOMSWorkspaceId)) { [OMSHelper]::PostOMSData($settings.AltOMSWorkspaceId, $settings.AltOMSSharedKey, $omsBodyByteArray, $OMSEventType) } } } } catch { [Exception] $ex = [Exception]::new(("Invalid OMS Settings: " + $_.Exception.ToString()), $_.Exception) throw [SuppressedException] $ex } } static [PSObject[]] ConvertToSimpleSet($contexts,[AzSKContextDetails] $AzSKContext) { $ControlSet = [System.Collections.ArrayList]::new() foreach ($item in $contexts) { $set = [OMSResourceInvModel]::new() $set.RunIdentifier = $AzSKContext.RunIdentifier $set.SubscriptionId = $item.SubscriptionContext.SubscriptionId $set.SubscriptionName = $item.SubscriptionContext.SubscriptionName $set.Source = $AzSKContext.Source $set.ScannerVersion = $AzSKContext.Version $set.FeatureName = $item.FeatureName if([Helpers]::CheckMember($item,"ResourceContext")) { $set.ResourceGroupName = $item.ResourceContext.ResourceGroupName $set.ResourceName = $item.ResourceContext.ResourceName $set.ResourceId = $item.ResourceContext.ResourceId } $set.ControlIntId = $item.ControlItem.Id $set.ControlId = $item.ControlItem.ControlID $set.ControlSeverity = $item.ControlItem.ControlSeverity $set.Tags = $item.ControlItem.Tags $set.IsBaselineControl = $item.ControlItem.IsBaselineControl $ControlSet.Add($set) } return $ControlSet; } #TODO: Find right place for this function static [void] SetOMSDetails() { #Check if Settings already contain details of OMS $settings = [ConfigurationManager]::GetAzSKSettings() #Step 1: if OMS details are not present on machine if([string]::IsNullOrWhiteSpace($settings.OMSWorkspaceId) -or [string]::IsNullOrWhiteSpace($settings.AltOMSWorkspaceId)) { $rgName = [ConfigurationManager]::GetAzSKConfigData().AzSKRGName #Step 2: Validate if CA is enabled on subscription $automationAccDetails= Get-AzureRmAutomationAccount -ResourceGroupName $rgName -ErrorAction SilentlyContinue if($automationAccDetails) { if([string]::IsNullOrWhiteSpace($settings.OMSWorkspaceId)) { #Step 3: Get workspace id from automation account variables $omsWorkSpaceId = Get-AzureRmAutomationVariable -ResourceGroupName $automationAccDetails.ResourceGroupName -AutomationAccountName $automationAccDetails.AutomationAccountName -Name "OMSWorkspaceId" -ErrorAction SilentlyContinue #Step 4: Get OMS with workspace id #TODO: Validate on sub where OMS not present if($omsWorkSpaceId) { $omsSharedKey = Get-AzureRmAutomationVariable -ResourceGroupName $automationAccDetails.ResourceGroupName -AutomationAccountName $automationAccDetails.AutomationAccountName -Name "OMSSharedKey" if([Helpers]::CheckMember($omsSharedKey,"Value") -and (-not [string]::IsNullOrWhiteSpace($omsSharedKey.Value))) { #Step 6: Assign it to AzSKSettings Object $settings.OMSWorkspaceId = $omsWorkSpaceId.Value $settings.OMSSharedKey = $omsSharedKey.Value } } } if([string]::IsNullOrWhiteSpace($settings.AltOMSWorkspaceId)) { #Step 3: Get workspace id from automation account variables $omsWorkSpaceId = Get-AzureRmAutomationVariable -ResourceGroupName $automationAccDetails.ResourceGroupName -AutomationAccountName $automationAccDetails.AutomationAccountName -Name "AltOMSWorkspaceId" -ErrorAction SilentlyContinue #Step 4: Get OMS with workspace id #TODO: Validate on sub where OMS not present if($omsWorkSpaceId) { $omsSharedKey = Get-AzureRmAutomationVariable -ResourceGroupName $automationAccDetails.ResourceGroupName -AutomationAccountName $automationAccDetails.AutomationAccountName -Name "AltOMSSharedKey" if([Helpers]::CheckMember($omsSharedKey,"Value") -and (-not [string]::IsNullOrWhiteSpace($omsSharedKey.Value))) { #Step 6: Assign it to AzSKSettings Object $settings.AltOMSWorkspaceId = $omsWorkSpaceId.Value $settings.AltOMSSharedKey = $omsSharedKey.Value } } } } } } static PostResourceInventory([AzSKContextDetails] $AzSKContext) { if($AzSKContext.Source.Equals("CC", [System.StringComparison]::OrdinalIgnoreCase) -or $AzSKContext.Source.Equals("CA", [System.StringComparison]::OrdinalIgnoreCase)){ $resourceSet = [System.Collections.ArrayList]::new() $resourcesFlat = Find-AzureRmResource $supportedResourceTypes = [SVTMapping]::GetSupportedResourceMap() # Not considering nested resources to reduce complexity $filteredResoruces = $resourcesFlat | Where-Object { $supportedResourceTypes.ContainsKey($_.ResourceType.ToLower()) } foreach($resource in $filteredResoruces){ $set = [OMSResourceModel]::new() $set.RunIdentifier = $AzSKContext.RunIdentifier $set.SubscriptionId = $resource.SubscriptionId #$set.SubscriptionName = $item.SubscriptionContext.SubscriptionName $set.Source = $AzSKContext.Source $set.ScannerVersion = $AzSKContext.Version $set.ResourceType = $resource.ResourceType $set.ResourceGroupName = $resource.ResourceGroupName $set.ResourceName = $resource.Name $set.ResourceId = $resource.ResourceId $resourceSet.Add($set) } [OMSHelper]::WriteControlResult($resourceSet,"AzSK_Inventory") $omsMetadata = [ConfigurationManager]::LoadServerConfigFile("OMSSettings.json") [OMSHelper]::WriteControlResult($omsMetadata,"AzSK_MetaData") } } } Class OMSModel { [string] $RunIdentifier [string] $ResourceType [string] $ResourceGroup [string] $Reference [string] $ResourceName [string] $ChildResourceName [string] $ResourceId [string] $ControlStatus [string] $ActualVerificationResult [string] $ControlId [string] $SubscriptionName [string] $SubscriptionId [string] $FeatureName [string] $Source [string] $Recommendation [string] $ControlSeverity [string] $TimeTakenInMs [string] $AttestationStatus [string] $AttestedBy [string] $Justification [string] $AttestedDate [bool] $HasRequiredAccess [bool] $HasAttestationWritePermissions [bool] $HasAttestationReadPermissions [bool] $IsLatestPSModule [string[]] $Tags [string] $ScannerVersion [bool] $IsBaselineControl [string] $ExpiryDate } Class OMSResourceInvModel{ [string] $RunIdentifier [string] $SubscriptionId [string] $SubscriptionName [string] $Source [string] $ScannerVersion [string] $FeatureName [string] $ResourceGroupName [string] $ResourceName [string] $ResourceId [string] $ControlId [string] $ControlIntId [string] $ControlSeverity [string[]] $Tags [bool] $IsBaselineControl } Class OMSResourceModel{ [string] $RunIdentifier [string] $SubscriptionId [string] $Source [string] $ScannerVersion [string] $ResourceType [string] $ResourceGroupName [string] $ResourceName [string] $ResourceId } Class AzSKContextDetails { [string] $RunIdentifier [string] $Version [string] $Source } |