Skip to content

Commit 8bcc63f

Browse files
a7mad-3bbasAhmad Abas
andauthored
Add vulnerability assessment cmdlets for IAAS in Az.Security (#14607)
* Add sql vulnerability assessment model * temp * Add Sql Vulnerability asessment model + Cmdlets implementation * add Documentation files * Fix design review comments * Add test scenario * Add Tests * Add vm domail label to creating vm in test * adjust the reference for monitoringSolutions * Change test category to live only. * Remove unnecessary dependencies * sync repo and update versions * update changelog.md * Fix PR comments * Modify mark down files and add examples * Rename baseline cmdlets * rename files for baseline cmdlets * Add Examples for set baseline cmdlet + some final adjustments to the documentation * Fixed PR comments. * Fix some static analysis issues * Add module name to cmdlets to distinguish them from PAAS cmdlets. * Rename files. * Add should process + rename help files. * update documentation. * fix rename issues from tests. Co-authored-by: Ahmad Abas <[email protected]>
1 parent dbcd519 commit 8bcc63f

File tree

36 files changed

+3319
-21
lines changed

36 files changed

+3319
-21
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// ----------------------------------------------------------------------------------
2+
//
3+
// Copyright Microsoft Corporation
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ----------------------------------------------------------------------------------
14+
15+
using Microsoft.Azure.Commands.ScenarioTest;
16+
using Microsoft.Azure.ServiceManagement.Common.Models;
17+
using Microsoft.WindowsAzure.Commands.ScenarioTest;
18+
using Xunit;
19+
20+
namespace Microsoft.Azure.Commands.Security.Test.ScenarioTests
21+
{
22+
public class SqlVulnerabilityAssessmentTests
23+
{
24+
private readonly XunitTracingInterceptor _logger;
25+
26+
public SqlVulnerabilityAssessmentTests(Xunit.Abstractions.ITestOutputHelper output)
27+
{
28+
_logger = new XunitTracingInterceptor(output);
29+
XunitTracingInterceptor.AddToContext(_logger);
30+
TestExecutionHelpers.SetUpSessionAndProfile();
31+
}
32+
33+
/*
34+
* This test is live only because it cannot be recorded.
35+
* New-AzMonitorLogAnalyticsSolution cmdlet depends on Az.MonitoringSolution
36+
* which is a generated module and is not currently supported by the testing framework
37+
*/
38+
[Fact]
39+
[Trait(Category.AcceptanceType, Category.LiveOnly)]
40+
public void TestAzSecuritySqlVulnerabilityAssessment()
41+
{
42+
TestController.NewInstance.RunPowerShellTest(_logger, "Test-AzSecuritySqlVulnerabilityAssessment");
43+
}
44+
}
45+
}
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
# ----------------------------------------------------------------------------------
2+
#
3+
# Copyright Microsoft Corporation
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
# ----------------------------------------------------------------------------------
14+
15+
<#
16+
.SYNOPSIS
17+
Tests end to end scenario for SQL vulnerability assessment on SQL VM.
18+
This test is live only because it cannot be recorded.
19+
New-AzMonitorLogAnalyticsSolution cmdlet depends on Az.MonitoringSolution
20+
which is a generated module and is not currently supported by the testing framework
21+
#>
22+
function Test-AzSecuritySqlVulnerabilityAssessment
23+
{
24+
# Setup
25+
$testPrefix = "pssqlva"
26+
$testParams = Get-SecuritySqlVulnerabilityAssessmentTestEnvironmentParameters $testPrefix
27+
$vmResourceId = "/subscriptions/" + $testParams.subscriptionId + "/resourceGroups/" + $testParams.rgName + "/providers/Microsoft.Compute/VirtualMachines/" + $testParams.sqlVmNamePrefix
28+
Create-TestEnvironmentWithParams $testParams
29+
30+
$vaScanRecord = Get-AzSecuritySqlVulnerabilityAssessmentScanRecord -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database master -ScanId latest
31+
$resultsOnMaster = Get-AzSecuritySqlVulnerabilityAssessmentScanResult -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database master
32+
$resultsWithFindingsOnMaster = $resultsOnMaster | where { $_.Status -eq "Finding" }
33+
34+
Assert-True { $resultsOnMaster.Count -eq $vaScanRecord.TotalRulesCount }
35+
Assert-True { $resultsWithFindingsOnMaster.Count -eq $vaScanRecord.TotalFailedRulesCount }
36+
37+
$finding = $resultsWithFindingsOnMaster | select -first 1
38+
$ruleResult = Get-AzSecuritySqlVulnerabilityAssessmentScanResult -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database master -ScanId $vaScanRecord.Name -RuleId $finding.Name
39+
40+
Assert-True { $finding.Name -eq $ruleResult.Name }
41+
42+
# check add baseline with latest.
43+
Add-AzSecuritySqlVulnerabilityAssessmentBaseline -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database master -RuleId $finding.Name
44+
45+
$baseline = Get-AzSecuritySqlVulnerabilityAssessmentBaseline -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database master -RuleId $finding.Name
46+
47+
Assert-NotNull $baseline
48+
49+
$baseline | Remove-AzSecuritySqlVulnerabilityAssessmentBaseline -Force
50+
51+
Assert-Throws { Get-AzSecuritySqlVulnerabilityAssessmentBaseline -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database master -RuleId $finding.Name }
52+
53+
# check Add baseline with result
54+
Add-AzSecuritySqlVulnerabilityAssessmentBaseline -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database master -RuleId $finding.Name -Baseline $finding.QueryResults
55+
56+
$baseline = Get-AzSecuritySqlVulnerabilityAssessmentBaseline -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database master -RuleId $finding.Name
57+
Assert-NotNull $baseline
58+
59+
$baseline | Remove-AzSecuritySqlVulnerabilityAssessmentBaseline -Force
60+
61+
### Check piping
62+
63+
$resultsOnMsdb = Get-AzSecuritySqlVulnerabilityAssessmentScanResult -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database msdb
64+
$resultsWithFindingsOnMsdb = $resultsOnMsdb | where { $_.Status -eq "Finding" }
65+
$rulesNamesOnMsdb = $resultsWithFindingsOnMsdb | select -ExpandProperty Name
66+
$rulesNamesOnMaster = $resultsWithFindingsOnMaster | select -ExpandProperty Name
67+
68+
# get rules intersection between master and msdb
69+
$ruleWithFindingsOnBothDbs = $rulesNamesOnMaster | ? {$rulesNamesOnMsdb -contains $_}
70+
71+
if ($ruleWithFindingsOnBothDbs.Count -gt 0)
72+
{
73+
# add baseline on master
74+
Add-AzSecuritySqlVulnerabilityAssessmentBaseline -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database master -RuleId $ruleWithFindingsOnBothDbs[0]
75+
76+
# bypass it to msdb
77+
Get-AzSecuritySqlVulnerabilityAssessmentBaseline -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database master -RuleId $ruleWithFindingsOnBothDbs[0] `
78+
| Add-AzSecuritySqlVulnerabilityAssessmentBaseline -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database msdb
79+
80+
$baseline = Get-AzSecuritySqlVulnerabilityAssessmentBaseline -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database msdb -RuleId $ruleWithFindingsOnBothDbs[0]
81+
Assert-NotNull $baseline
82+
}
83+
84+
# Set all latest results as Baseline
85+
Set-AzSecuritySqlVulnerabilityAssessmentBaseline -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database master -Force
86+
$vaScanRecord = Get-AzSecuritySqlVulnerabilityAssessmentScanRecord -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database master -ScanId latest
87+
88+
Assert-True { $vaScanRecord.State -eq "Passed"}
89+
Assert-True { $vaScanRecord.TotalFailedRulesCount -eq 0 }
90+
91+
Get-AzSecuritySqlVulnerabilityAssessmentBaseline -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database master | Remove-AzSecuritySqlVulnerabilityAssessmentBaseline -Force
92+
93+
$baselineSet = @{}
94+
$resultsWithFindingsOnMaster | select -skip 3 | ForEach-Object { $baselineSet.Add($_.RuleId, $_.QueryResults)}
95+
96+
Set-AzSecuritySqlVulnerabilityAssessmentBaseline -ResourceId $vmResourceId -WorkspaceId $testParams.workspaceId -Server $testParams.sqlServerName -Database master -BaselineSet $baselineSet -Force
97+
98+
Delete-TestEnvironments ($testParams)
99+
}
100+
101+
<#
102+
.SYNOPSIS
103+
Gets the values of the parameters used at the tests
104+
#>
105+
function Get-SecuritySqlVulnerabilityAssessmentTestEnvironmentParameters ($testPrefix)
106+
{
107+
$location = Get-Location "Microsoft.Compute" "virtualMachines" "East Us 2 Euap";
108+
$sqlVmName = getAssetName ($testPrefix +'vm');
109+
110+
return @{ subscriptionId = (Get-AzContext).Subscription.Id;
111+
rgName = getAssetName ($testPrefix);
112+
sqlVmNamePrefix = $sqlVmName;
113+
sqlVmDomain_prefix = 'domainvm';
114+
sqlVmMaxLength = 15;
115+
sqlVmUserName = 'testuser';
116+
sqlVmPassword = Generate-RandomVmPassword;
117+
sqlServerImage = 'MicrosoftSQLServer:SQL2017-WS2016:Enterprise:latest';
118+
sqlServerVmSize = 'Standard_DS2_v2';
119+
sqlServerName = "MSSQLSERVER"
120+
operationalInsightsWorkspaceName = getAssetName ($testPrefix +"psWorkspace");
121+
workspaceId = "";
122+
location = location;
123+
vmLocation = $location.Replace(' ', '');
124+
vmDomainNameLabel = (getAssetName ($sqlVmName +'-')).ToLower();
125+
}
126+
127+
}
128+
129+
<#
130+
.SYNOPSIS
131+
Creates the basic test environment needed to perform the sql vulnerability assessment tests - resource group, VM, workspace,... etc
132+
#>
133+
function Create-TestEnvironmentWithParams ($testParams)
134+
{
135+
# Create a new resource group.
136+
New-AzResourceGroup -Name $testParams.rgName -Location $testParams.location
137+
138+
$passWord = ConvertTo-SecureString -String $testParams.sqlVmPassword -AsPlainText -Force
139+
$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $testParams.sqlVmUserName, $passWord
140+
141+
# Create the sql virtual machine.
142+
Write-Host "ResourceGroupName " + $testParams.rgName + " -Location " + $testParams.location " -Size "+ $testParams.sqlServerVmSize + " -Image " + $testParams.sqlServerImage + " -Credential " + $cred " -Name " + $testParams.sqlVmNamePrefix
143+
144+
New-AzVm -ResourceGroupName $testParams.rgName -Location $testParams.vmLocation -Image $testParams.sqlServerImage -Credential $cred -Name $testParams.sqlVmNamePrefix -DomainNameLabel $testParams.vmDomainNameLabel
145+
146+
# Create the log analytics worskspace
147+
$workspace = New-AzOperationalInsightsWorkspace -Location $testParams.location -Name $testParams.operationalInsightsWorkspaceName -ResourceGroupName $testParams.rgName
148+
New-AzMonitorLogAnalyticsSolution -Type SQLVulnerabilityAssessment -ResourceGroupName $testParams.rgName -Location $testParams.location -WorkspaceResourceId $workspace.ResourceId
149+
150+
# Install microsoft Monitoring agent on the VM
151+
$workspaceKeys = Get-AzOperationalInsightsWorkspaceSharedKey -Name $testParams.operationalInsightsWorkspaceName -ResourceGroupName $testParams.rgName
152+
$publicSettings = @{"workspaceId" = $workspace.CustomerId}
153+
$protectedSettings = @{"workspaceKey" = $workspaceKeys.PrimarySharedKey}
154+
155+
$testParams.workspaceId = $workspace.CustomerId;
156+
157+
Set-AzVMExtension -ExtensionName "MicrosoftMonitoringAgent" `
158+
-ResourceGroupName $testParams.rgName `
159+
-VMName $testParams.sqlVmNamePrefix`
160+
-Publisher "Microsoft.EnterpriseCloud.Monitoring" `
161+
-ExtensionType "MicrosoftMonitoringAgent" `
162+
-TypeHandlerVersion 1.0 `
163+
-Settings $publicSettings `
164+
-ProtectedSettings $protectedSettings `
165+
-Location $testParams.vmLocation
166+
167+
# Update the registery and restart the Monitoring agent to force a scan.
168+
Invoke-AzVMRunCommand -ResourceGroupName $testParams.rgName -Name $testParams.sqlVmNamePrefix -CommandId 'RunPowerShellScript' -ScriptPath 'SqlVulnerabilityAssessmentTestResources\SetUpVm.ps1'
169+
170+
Start-Sleep -Seconds 180
171+
}
172+
173+
<#
174+
.SYNOPSIS
175+
Deletes the Test enviroment once the test passes.
176+
#>
177+
function Delete-TestEnvironments ($testParams)
178+
{
179+
New-AzResourceGroup -Name $testParams.rgName
180+
}
181+
182+
<#
183+
.SYNOPSIS
184+
Generates a random password for vm that satisfies these conditions:
185+
- At least 15 character long
186+
- Contains at at least one number
187+
- Contains at least one lower case letter
188+
- Contains at least one upper case letter
189+
#>
190+
function Generate-RandomVmPassword()
191+
{
192+
$password = ("abcdefghijklmnopqrstuvwxyz".tochararray() | sort {Get-Random})[0..4] -join ''
193+
$password += ("ABCDEFGHIJKLMNOPQRSTUVWXYZ".tochararray() | sort {Get-Random})[0..7] -join ''
194+
$password += ("0123456789".tochararray() | sort {Get-Random})[0..4] -join ''
195+
196+
return ($password.tochararray() | sort {Get-Random}) -join ''
197+
}

src/Security/Security.Test/ScenarioTests/TestController.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
// ----------------------------------------------------------------------------------
1414

1515
using Microsoft.Azure.Commands.Common.Authentication;
16+
using Microsoft.Azure.Management.Compute;
17+
using Microsoft.Azure.Management.OperationalInsights;
18+
using Microsoft.Azure.Management.Internal.Network.Version2017_10_01;
1619
using Microsoft.Azure.Management.Internal.Resources;
1720
using Microsoft.Azure.Management.Security;
1821
using Microsoft.Azure.Management.Storage.Version2017_10_01;
@@ -56,12 +59,18 @@ public void RunPowerShellTest(ServiceManagement.Common.Models.XunitTracingInterc
5659
SetupManagementClients(context);
5760

5861
_helper.SetupEnvironment(AzureModule.AzureResourceManager);
62+
var computePath = _helper.GetRMModulePath(@"AzureRM.Compute.psd1");
63+
var networkPath = _helper.GetRMModulePath(@"AzureRM.Network.psd1");
64+
var operationalInsightsPath = _helper.GetRMModulePath(@"AzureRM.OperationalInsights.psd1");
5965

6066
var callingClassName = callingClassType?.Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries).Last();
6167
_helper.SetupModules(
6268
AzureModule.AzureResourceManager,
6369
_helper.RMProfileModule,
6470
_helper.GetRMModulePath(@"AzureRM.Security.psd1"),
71+
computePath,
72+
networkPath,
73+
operationalInsightsPath,
6574
"ScenarioTests\\Common.ps1",
6675
"ScenarioTests\\" + callingClassName + ".ps1",
6776
"AzureRM.Storage.ps1",
@@ -76,7 +85,10 @@ protected void SetupManagementClients(MockContext context)
7685
var resourcesClient = GetResourcesClient(context);
7786
var securityCenterClient = GetSecurityCenterClient(context);
7887
var storageClient = GetStorageManagementClient(context);
79-
_helper.SetupManagementClients(securityCenterClient, resourcesClient, storageClient);
88+
var computeClient = GetComputeManagementClient(context);
89+
var networkClient = GetNetworkManagementClient(context);
90+
var operationalInsightsClient = GetOperationalInsightsManagementClient(context);
91+
_helper.SetupManagementClients(securityCenterClient, resourcesClient, storageClient, computeClient, networkClient, operationalInsightsClient);
8092
}
8193

8294
private static SecurityCenterClient GetSecurityCenterClient(MockContext context)
@@ -91,5 +103,20 @@ private static StorageManagementClient GetStorageManagementClient(MockContext co
91103
{
92104
return context.GetServiceClient<StorageManagementClient>(TestEnvironmentFactory.GetTestEnvironment());
93105
}
106+
107+
private static ComputeManagementClient GetComputeManagementClient(MockContext context)
108+
{
109+
return context.GetServiceClient<ComputeManagementClient>(TestEnvironmentFactory.GetTestEnvironment());
110+
}
111+
112+
private static NetworkManagementClient GetNetworkManagementClient(MockContext context)
113+
{
114+
return context.GetServiceClient<NetworkManagementClient>(TestEnvironmentFactory.GetTestEnvironment());
115+
}
116+
117+
private static OperationalInsightsManagementClient GetOperationalInsightsManagementClient(MockContext context)
118+
{
119+
return context.GetServiceClient<OperationalInsightsManagementClient>(TestEnvironmentFactory.GetTestEnvironment());
120+
}
94121
}
95122
}

src/Security/Security.Test/Security.Test.csproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@
3838
<None Include="SqlInformationProtectionPolicies\SensitivityLabelsSharingSameId.json">
3939
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
4040
</None>
41+
<None Update="SqlVulnerabilityAssessmentTestResources\SetUpVM.ps1">
42+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
43+
</None>
4144
<PackageReference Include="Microsoft.Azure.Management.SecurityCenter" Version="2.2.0" />
45+
<PackageReference Include="Microsoft.Azure.Management.Compute" Version="44.0.0" />
46+
<PackageReference Include="Microsoft.Azure.Management.OperationalInsights" Version="0.21.0-preview" />
4247
</ItemGroup>
43-
4448
</Project>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
New-Item -ItemType Directory -Force -Path C:\\Users\\testuser\\Desktop\\Va_Logs\
2+
New-Item -ItemType Directory -Force -Path C:\\Users\\testuser\\Desktop\\Setup_Logs\
3+
New-Item -Path HKLM:\\Software\\Microsoft\\AzureOperationalInsights\
4+
Set-ItemProperty -Path HKLM:\\Software\\Microsoft\\AzureOperationalInsights -Name SqlVulnerabilityAssessment_LogDirectoryPath -Value C:\\Users\\testuser\\Desktop\\Va_Logs\
5+
Set-ItemProperty -Path HKLM:\\Software\\Microsoft\\AzureOperationalInsights -Name SqlVulnerabilityAssessment_BypassHashCheck -Value true\
6+
Set-ItemProperty -Path HKLM:\\Software\\Microsoft\\AzureOperationalInsights -Name SqlVulnerabilityAssessment_TestMachine -Value true
7+
8+
Start-Sleep -Seconds 60
9+
Restart-Service HealthService

src/Security/Security/Az.Security.psd1

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ CmdletsToExport = 'Get-AzSecurityAlert', 'Set-AzSecurityAlert',
8989
'Get-AzSecurityAdvancedThreatProtection',
9090
'Enable-AzSecurityAdvancedThreatProtection',
9191
'Disable-AzSecurityAdvancedThreatProtection',
92+
'Get-AzSecuritySqlVulnerabilityAssessmentScanRecord',
93+
'Get-AzSecuritySqlVulnerabilityAssessmentScanResult',
94+
'Add-AzSecuritySqlVulnerabilityAssessmentBaseline',
95+
'Remove-AzSecuritySqlVulnerabilityAssessmentBaseline',
96+
'Get-AzSecuritySqlVulnerabilityAssessmentBaseline',
97+
'Set-AzSecuritySqlVulnerabilityAssessmentBaseline',
9298
'Get-AzIotSecuritySolution', 'Set-AzIotSecuritySolution',
9399
'Remove-AzIotSecuritySolution', 'Update-AzIotSecuritySolution',
94100
'New-AzIotSecuritySolutionRecommendationConfigurationObject',

0 commit comments

Comments
 (0)