Framework/Listeners/RemoteReports/RemoteReportsListner.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
Set-StrictMode -Version Latest

class RemoteReportsListner: ListenerBase {

    hidden RemoteReportsListner() {
    }

    hidden static [RemoteReportsListner] $Instance = $null;

    static [RemoteReportsListner] GetInstance() {
        if ( $null  -eq [RemoteReportsListner]::Instance  ) {
            [RemoteReportsListner]::Instance = [RemoteReportsListner]::new();
        }
        return [RemoteReportsListner]::Instance
    }

    [void] RegisterEvents() {
        $this.UnregisterEvents();

        $this.RegisterEvent([AzSKRootEvent]::GenerateRunIdentifier, {
            $currentInstance = [RemoteReportsListner]::GetInstance();
            try
            {
                $runIdentifier = [AzSKRootEventArgument] ($Event.SourceArgs | Select-Object -First 1)
                $currentInstance.SetRunIdentifier($runIdentifier);
            }
            catch
            {
                $currentInstance.PublishException($_);
            }
        });

        $this.RegisterEvent([SVTEvent]::CommandStarted, {
             $currentInstance = [RemoteReportsListner]::GetInstance();
            try
            {

                $scanSource = [RemoteReportHelper]::GetScanSource();
                if($scanSource -ne [ScanSource]::Runbook) { return; }
                [RemoteReportsListner]::ReportAllResources();

                $invocationContext = [System.Management.Automation.InvocationInfo] $currentInstance.InvocationContext
                if(!$invocationContext.BoundParameters.ContainsKey("SubscriptionId")) {return;}
                $resources = "" | Select-Object "SubscriptionId", "ResourceGroups"
                $resources.SubscriptionId = $invocationContext.BoundParameters["SubscriptionId"]
                $resources.ResourceGroups = [System.Collections.ArrayList]::new()
                $resourcesFlat = Find-AzureRmResource
                $supportedResourceTypes = [SVTMapping]::GetSupportedResourceMap()
                # Not considering nested resources to reduce complexity
                $filteredResoruces = $resourcesFlat | where { $supportedResourceTypes.ContainsKey($_.ResourceType.ToLower()) }
                $grouped = $filteredResoruces | Group-Object {$_.ResourceGroupName} | Select-Object Name, Group
                foreach($group in $grouped){
                    $resourceGroup = "" | Select-Object Name, Resources
                    $resourceGroup.Name = $group.Name
                    $resourceGroup.Resources = [System.Collections.ArrayList]::new()
                    foreach($item in $group.Group){
                        $resource = "" | Select-Object Name, ResourceId, Feature
                        if($item.Name.Contains("/")){
                            $splitName = $item.Name.Split("/")
                            $resource.Name = $splitName[$splitName.Length - 1]
                        }
                        else{
                            $resource.Name = $item.Name;
                        }
                        $resource.ResourceId = $item.ResourceId
                        $resource.Feature = $supportedResourceTypes[$item.ResourceType.ToLower()]
                        $resourceGroup.Resources.Add($resource) | Out-Null
                    }
                    $resources.ResourceGroups.Add($resourceGroup) | Out-Null
                }
                [RemoteApiHelper]::PostResourceInventory($resources)
            }
            catch
            {
                $currentInstance.PublishException($_);
            }
        });

        $this.RegisterEvent([SVTEvent]::EvaluationCompleted, {
            $currentInstance = [RemoteReportsListner]::GetInstance();
            try
            {
                $settings = [ConfigurationManager]::GetAzSKConfigData();
                if(!$settings.PublishVulnDataToApi) {return;}
                $invocationContext = [System.Management.Automation.InvocationInfo] $currentInstance.InvocationContext
                $SVTEventContexts = [SVTEventContext[]] $Event.SourceArgs
                $featureGroup = [RemoteReportHelper]::GetFeatureGroup($SVTEventContexts)
                if($featureGroup -eq [FeatureGroup]::Subscription){
                    [RemoteReportsListner]::ReportSubscriptionScan($currentInstance, $invocationContext, $SVTEventContexts)
                }elseif($featureGroup -eq [FeatureGroup]::Service){
                    [RemoteReportsListner]::ReportServiceScan($currentInstance, $invocationContext, $SVTEventContexts)
                }else{

                }
            }
            catch
            {
                $currentInstance.PublishException($_);
            }
        });

        $this.RegisterEvent([AzSKRootEvent]::PublishCustomData, {
            $currentInstance = [RemoteReportsListner]::GetInstance();
            try
            {
                
                $CustomDataObj =  $Event.SourceArgs
                $CustomObjectValue=$CustomDataObj| select -exp Messages|select -exp DataObject| select -exp Value;
                [RemoteApiHelper]::PostRBACTelemetry($CustomObjectValue);
            }
            catch
            {
                $currentInstance.PublishException($_);
            }
        });

        
    }


    static [void] ReportAllResources()
    {
        $currentInstance = [RemoteReportsListner]::GetInstance();
        $invocationContext = [System.Management.Automation.InvocationInfo] $currentInstance.InvocationContext
        $resourcesFlat = Find-AzureRmResource
        [RemoteApiHelper]::PostResourceFlatInventory($resourcesFlat)

    }


    static [void] ReportSubscriptionScan(
        [RemoteReportsListner] $publisher, `
        [System.Management.Automation.InvocationInfo]  $invocationContext, `
        [SVTEventContext[]] $SVTEventContexts)
    {
        $SVTEventContext = $SVTEventContexts[0]
        $scanResult = [SubscriptionScanInfo]::new()
        $scanResult.ScanKind = [RemoteReportHelper]::GetSubscriptionScanKind($invocationContext.MyCommand.Name, $invocationContext.BoundParameters)
        $scanResult.SubscriptionId = $SVTEventContext.SubscriptionContext.SubscriptionId
        $scanResult.SubscriptionName = $SVTEventContext.SubscriptionContext.SubscriptionName
        $scanResult.Source = [RemoteReportHelper]::GetScanSource()
        $scanResult.ScannerVersion = $publisher.GetCurrentModuleVersion()
        # TODO: Figure out, temp using module version
        $scanResult.ControlVersion = $publisher.GetCurrentModuleVersion()
        $scanResult.Metadata = [Helpers]::ConvertToJsonCustomCompressed($SVTEventContext.SubscriptionContext.SubscriptionMetadata)
        if(($SVTEventContexts | Measure-Object).Count -gt 0 -and ($SVTEventContexts[0].ControlResults | Measure-Object).Count -gt 0)
        {
            $TempCtrlResult = $SVTEventContexts[0].ControlResults[0];
            $scanResult.HasAttestationWritePermissions = $TempCtrlResult.CurrentSessionContext.Permissions.HasAttestationWritePermissions
            $scanResult.HasAttestationReadPermissions = $TempCtrlResult.CurrentSessionContext.Permissions.HasAttestationReadPermissions
            $scanResult.IsLatestPSModule = $TempCtrlResult.CurrentSessionContext.IsLatestPSModule
        }
        $results = [System.Collections.ArrayList]::new()
        $SVTEventContexts | ForEach-Object {
            $context = $_
            if ($context.ControlItem.Enabled) {
                $result = [RemoteReportHelper]::BuildSubscriptionControlResult($context.ControlResults[0], $context.ControlItem)
                $results.Add($result)
            }
            else {
                $result = [SubscriptionControlResult]::new()
                $result.ControlId = $context.ControlItem.ControlID
                $result.ControlIntId = $context.ControlItem.Id
                $result.ActualVerificationResult = [VerificationResult]::Disabled
                $result.AttestationStatus = [AttestationStatus]::None
                $result.VerificationResult = [VerificationResult]::Disabled
                $results.Add($result)
            }
        }
        $scanResult.ControlResults = [SubscriptionControlResult[]] $results
        [RemoteApiHelper]::PostSubscriptionScanResult($scanResult)
    }

    static [void] ReportServiceScan(
        [RemoteReportsListner] $publisher, `
        [System.Management.Automation.InvocationInfo]  $invocationContext, `
        [SVTEventContext[]] $SVTEventContexts)
    {
        $SVTEventContextFirst = $SVTEventContexts[0]
        $scanResult = [ServiceScanInfo]::new()
        $scanResult.ScanKind = [RemoteReportHelper]::GetServiceScanKind($invocationContext.MyCommand.Name, $invocationContext.BoundParameters)
        $scanResult.SubscriptionId = $SVTEventContextFirst.SubscriptionContext.SubscriptionId
        $scanResult.SubscriptionName = $SVTEventContextFirst.SubscriptionContext.SubscriptionName
        $scanResult.Source = [RemoteReportHelper]::GetScanSource()
        $scanResult.ScannerVersion = $publisher.GetCurrentModuleVersion()
        # TODO: Figure out, temp using module version
        $scanResult.ControlVersion = $publisher.GetCurrentModuleVersion()
        $scanResult.Feature = $SVTEventContextFirst.FeatureName
        $scanResult.ResourceGroup = $SVTEventContextFirst.ResourceContext.ResourceGroupName
        $scanResult.ResourceName = $SVTEventContextFirst.ResourceContext.ResourceName
        $scanResult.ResourceId = $SVTEventContextFirst.ResourceContext.ResourceId
        $scanResult.Metadata = [Helpers]::ConvertToJsonCustomCompressed($SVTEventContextFirst.ResourceContext.ResourceMetadata)
        if(($SVTEventContexts | Measure-Object).Count -gt 0 -and ($SVTEventContexts[0].ControlResults | Measure-Object).Count -gt 0)
        {
            $TempCtrlResult = $SVTEventContexts[0].ControlResults[0];
            $scanResult.HasAttestationWritePermissions = $TempCtrlResult.CurrentSessionContext.Permissions.HasAttestationWritePermissions
            $scanResult.HasAttestationReadPermissions = $TempCtrlResult.CurrentSessionContext.Permissions.HasAttestationReadPermissions
            $scanResult.IsLatestPSModule = $TempCtrlResult.CurrentSessionContext.IsLatestPSModule
        }
        $results = [System.Collections.ArrayList]::new()
        $SVTEventContexts | ForEach-Object {
            $SVTEventContext = $_
            if (!$SVTEventContext.ControlItem.Enabled) {
                $result = [ServiceControlResult]::new()
                $result.ControlId = $SVTEventContext.ControlItem.ControlID
                $result.ControlIntId = $SVTEventContext.ControlItem.Id
                $result.ControlSeverity = $SVTEventContext.ControlItem.ControlSeverity
                $result.ActualVerificationResult = [VerificationResult]::Disabled
                $result.AttestationStatus = [AttestationStatus]::None
                $result.VerificationResult = [VerificationResult]::Disabled
                $results.Add($result)
            }
            elseif ($SVTEventContext.ControlResults.Count -eq 1 -and `
                ($scanResult.ResourceName -eq $SVTEventContext.ControlResults[0].ChildResourceName -or `
                    [string]::IsNullOrWhiteSpace($SVTEventContext.ControlResults[0].ChildResourceName)))
            {
                $result = [RemoteReportHelper]::BuildServiceControlResult($SVTEventContext.ControlResults[0], `
                    $false, $SVTEventContext.ControlItem)
                $results.Add($result)
            }
            elseif ($SVTEventContext.ControlResults.Count -eq 1 -and `
                $scanResult.ResourceName -ne $SVTEventContext.ControlResults[0].ChildResourceName)
            {
                $result = [RemoteReportHelper]::BuildServiceControlResult($SVTEventContext.ControlResults[0], `
                     $true, $SVTEventContext.ControlItem)
                $results.Add($result)
            }
            elseif ($SVTEventContext.ControlResults.Count -gt 1)
            {
                $SVTEventContext.ControlResults | Foreach-Object {
                    $result = [RemoteReportHelper]::BuildServiceControlResult($_ , `
                         $true, $SVTEventContext.ControlItem)
                    $results.Add($result)
                }
            }
        }
        $scanResult.ControlResults = [ServiceControlResult[]] $results
        [RemoteApiHelper]::PostServiceScanResult($scanResult)
    }
}