Skip to content

Commit

Permalink
Add option to generate a config file template (#984)
Browse files Browse the repository at this point in the history
* config file generation

* Adding defender

* Final generate config file

* Ready for pull request

* moved to support module

* added to manifest file

* pascal case and whitespace

* linter hacks

* linter test

* "unused" variables

* linter hacks part II

* linter hacks part III

* Unit Test added

* added default value for unit testing

various syntax fixes as well

* fixed unit test, mock converting to yaml

* fixed unit tests?

* fixed?

* more debugging

* debugging

* Update README.md for generating config
  • Loading branch information
amart241 committed Mar 28, 2024
1 parent 8bed58c commit 9128a12
Show file tree
Hide file tree
Showing 6 changed files with 314 additions and 5 deletions.
255 changes: 254 additions & 1 deletion PowerShell/ScubaGear/Modules/Support/Support.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -648,11 +648,264 @@ function Copy-ScubaModuleFile {
}
}

function New-Config {
<#
.SYNOPSIS
Generate a config file for the ScubaGear tool
.Description
Using provided user input generate a config file to run ScubaGear tailored to the end user
.Parameter ProductNames
A list of one or more M365 shortened product names that the tool will assess when it is executed. Acceptable product name values are listed below.
To assess Azure Active Directory you would enter the value aad.
To assess Exchange Online you would enter exo and so forth.
- Azure Active Directory: aad
- Defender for Office 365: defender
- Exchange Online: exo
- MS Power Platform: powerplatform
- SharePoint Online: sharepoint
- MS Teams: teams.
Use '*' to run all baselines.
.Parameter M365Environment
This parameter is used to authenticate to the different commercial/government environments.
Valid values include "commercial", "gcc", "gcchigh", or "dod".
- For M365 tenants with E3/E5 licenses enter the value **"commercial"**.
- For M365 Government Commercial Cloud tenants with G3/G5 licenses enter the value **"gcc"**.
- For M365 Government Commercial Cloud High tenants enter the value **"gcchigh"**.
- For M365 Department of Defense tenants enter the value **"dod"**.
Default value is 'commercial'.
.Parameter OPAPath
The folder location of the OPA Rego executable file.
The OPA Rego executable embedded with this project is located in the project's root folder.
If you want to execute the tool using a version of OPA Rego located in another folder,
then customize the variable value with the full path to the alternative OPA Rego exe file.
.Parameter LogIn
A `$true` or `$false` variable that if set to `$true`
will prompt you to provide credentials if you want to establish a connection
to the specified M365 products in the **$ProductNames** variable.
For most use cases, leave this variable to be `$true`.
A connection is established in the current PowerShell terminal session with the first authentication.
If you want to run another verification in the same PowerShell session simply set
this variable to be `$false` to bypass the reauthenticating in the same session. Default is $true.
Note: defender will ask for authentication even if this variable is set to `$false`
;;;.Parameter Version
;;;Will output the current ScubaGear version to the terminal without running this cmdlet.
.Parameter AppID
The application ID of the service principal that's used during certificate based
authentication. A valid value is the GUID of the application ID (service principal).
.Parameter CertificateThumbprint
The thumbprint value specifies the certificate that's used for certificate base authentication.
The underlying PowerShell modules retrieve the certificate from the user's certificate store.
As such, a copy of the certificate must be located there.
.Parameter Organization
Specify the organization that's used in certificate based authentication.
Use the tenant's tenantname.onmicrosoft.com domain for the parameter value.
.Parameter OutPath
The folder path where both the output JSON and the HTML report will be created.
The folder will be created if it does not exist. Defaults to current directory.
.Parameter OutFolderName
The name of the folder in OutPath where both the output JSON and the HTML report will be created.
Defaults to "M365BaselineConformance". The client's local timestamp will be appended.
.Parameter OutProviderFileName
The name of the Provider output JSON created in the folder created in OutPath.
Defaults to "ProviderSettingsExport".
.Parameter OutRegoFileName
The name of the Rego output JSON and CSV created in the folder created in OutPath.
Defaults to "TestResults".
.Parameter OutReportName
The name of the main html file page created in the folder created in OutPath.
Defaults to "BaselineReports".
.Parameter DisconnectOnExit
Set switch to disconnect all active connections on exit from ScubaGear (default: $false)
.Parameter ConfigFilePath
Local file path to a JSON or YAML formatted configuration file.
Configuration file parameters can be used in place of command-line
parameters. Additional parameters and variables not available on the
command line can also be included in the file that will be provided to the
tool for use in specific tests.
.Functionality
Public
#>
[CmdletBinding(DefaultParameterSetName='Report')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
param (

[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]
$Description = "YAML configuration file with default description", #(Join-Path -Path $env:USERPROFILE -ChildPath ".scubagear\Tools"),

[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[ValidateSet("teams", "exo", "defender", "aad", "powerplatform", "sharepoint", '*', IgnoreCase = $false)]
[string[]]
$ProductNames = @("aad", "defender", "exo", "sharepoint", "teams"),

[Parameter(Mandatory = $false)]
[ValidateSet("commercial", "gcc", "gcchigh", "dod", IgnoreCase = $false)]
[ValidateNotNullOrEmpty()]
[string]
$M365Environment = "commercial",

[Parameter(Mandatory = $false)]
[ValidateScript({Test-Path -PathType Container $_})]
[string]
$OPAPath = ".", #(Join-Path -Path $env:USERPROFILE -ChildPath ".scubagear\Tools"),

[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[ValidateSet($true, $false)]
[boolean]
$LogIn = $true,

[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[ValidateSet($true, $false)]
[boolean]
$DisconnectOnExit = $false,

[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]
$OutPath = '.',

[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]
$AppID,

[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]
$CertificateThumbprint,

[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]
$Organization,

[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]
$OutFolderName = "M365BaselineConformance",

[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]
$OutProviderFileName = "ProviderSettingsExport",

[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]
$OutRegoFileName = "TestResults",

[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]
$OutReportName = "BaselineReports",

[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]
$ConfigLocation = "./"
)

$Config = New-Object ([System.Collections.specialized.OrderedDictionary])

($MyInvocation.MyCommand.Parameters ).Keys | ForEach-Object{
$Val = (Get-Variable -Name $_ -EA SilentlyContinue).Value
if( $Val.length -gt 0 ) {
#$config[$_] = $val
$Config.add($_, $Val)
}
}

$CapExclusionNamespace = @(
"MS.AAD.1.1v1",
"MS.AAD.2.1v1",
"MS.AAD.2.3v1",
"MS.AAD.3.1v1",
"MS.AAD.3.2v1",
"MS.AAD.3.3v1",
"MS.AAD.3.6v1",
"MS.AAD.3.7v1",
"MS.AAD.3.8v1"
)
$RoleExclusionNamespace = "MS.AAD.7.4v1"

$CommonSensitiveAccountFilterNamespace = @(
"MS.DEFENDER.1.4v1",
"MS.DEFENDER.1.5v1"
)

$UserImpersonationProtectionNamespace = "MS.DEFENDER.2.1v1"

$AgencyDomainImpersonationProtectionNamespace = "MS.DEFENDER.2.2v1"

$PartnerDomainImpersonationProtectionNamespace = "MS.DEFENDER.2.3v1"


$AadTemplate = New-Object ([System.Collections.specialized.OrderedDictionary])
$AadCapExclusions = New-Object ([System.Collections.specialized.OrderedDictionary])
$AadRoleExclusions = New-Object ([System.Collections.specialized.OrderedDictionary])

$DefenderTemplate = New-Object ([System.Collections.specialized.OrderedDictionary])
$DefenderCommonSensitiveAccountFilter = New-Object ([System.Collections.specialized.OrderedDictionary])
#$defenderUserImpersonationProtection = New-Object ([System.Collections.specialized.OrderedDictionary])
#$defenderAgencyDomainImpersonationProtection = New-Object ([System.Collections.specialized.OrderedDictionary])
#$defenderPartnerDomainImpersonationProtection = New-Object ([System.Collections.specialized.OrderedDictionary])



$AadCapExclusions = @{ CapExclusions = @{} }
$AadCapExclusions["CapExclusions"].add("Users", @(""))
$AadCapExclusions["CapExclusions"].add("Groups", @(""))

$AadRoleExclusions = @{ RoleExclusions = @{} }
$AadRoleExclusions["RoleExclusions"].add("Users", @(""))
$AadRoleExclusions["RoleExclusions"].add("Groups", @(""))

foreach ($Cap in $CapExclusionNamespace){
$AadTemplate.add($Cap, $AadCapExclusions)
}

$AadTemplate.add($RoleExclusionNamespace, $AadRoleExclusions)

$DefenderCommonSensitiveAccountFilter = @{ SensitiveAccounts = @{} }
$DefenderCommonSensitiveAccountFilter['SensitiveAccounts'].add("IncludedUsers", @(""))
$DefenderCommonSensitiveAccountFilter['SensitiveAccounts'].add("IncludedGroups", @(""))
$DefenderCommonSensitiveAccountFilter['SensitiveAccounts'].add("IncludedDomains", @(""))
$DefenderCommonSensitiveAccountFilter['SensitiveAccounts'].add("ExcludedUsers", @(""))
$DefenderCommonSensitiveAccountFilter['SensitiveAccounts'].add("ExcludedGroups", @(""))
$DefenderCommonSensitiveAccountFilter['SensitiveAccounts'].add("ExcludedDomains", @(""))

foreach ($Filter in $CommonSensitiveAccountFilterNamespace){
$DefenderTemplate.add($Filter, $DefenderCommonSensitiveAccountFilter)
}

$DefenderTemplate.add($UserImpersonationProtectionNamespace, @{ SensitiveUsers = @("") })
$DefenderTemplate.add($AgencyDomainImpersonationProtectionNamespace, @{ AgencyDomains = @("") })
$DefenderTemplate.add($PartnerDomainImpersonationProtectionNamespace, @{ PartnerDomains = @("") })

$Products = (Get-Variable -Name ProductNames -EA SilentlyContinue).Value
foreach ($Product in $Products){
switch ($Product){
"aad" {
$config.add("Aad", $AadTemplate)
}
"defender" {
$config.add("Defender", $DefenderTemplate)
}
}
}
convertto-yaml $Config | set-content "$($ConfigLocation)/SampleConfig.yaml"
}

Export-ModuleMember -Function @(
'Copy-ScubaBaselineDocument',
'Install-OPA',
'Initialize-SCuBA',
'Debug-SCuBA',
'Copy-ScubaSampleReport',
'Copy-ScubaSampleConfigFile'
'Copy-ScubaSampleConfigFile',
'New-Config'
)
3 changes: 2 additions & 1 deletion PowerShell/ScubaGear/ScubaGear.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ FunctionsToExport = @(
'Initialize-SCuBA',
'Debug-SCuBA',
'Copy-ScubaSampleReport',
'Copy-ScubaSampleConfigFile'
'Copy-ScubaSampleConfigFile',
'New-Config'
)

# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ InModuleScope CreateReport {
$Output.aad.Controls[1].MalformedDescription | Should -BeFalse -Because "Only warning for MS.AAD.2.1v1 policy description with to many lines."
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,4 @@ InModuleScope CreateReport {
AfterAll {
Remove-Module CreateReport -ErrorAction SilentlyContinue
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath '../../../../Modules/Support')

InModuleScope Support {
Describe -Tag Support -Name 'New-Config' {
BeforeAll {

[Flags()]
enum SerializationOptions {
None = 0
Roundtrip = 1
DisableAliases = 2
EmitDefaults = 4
JsonCompatible = 8
DefaultToStaticType = 16
WithIndentedSequences = 32
}

Mock -CommandName Write-Warning {}

function ConvertTo-Yaml {throw 'this will be mocked'}
Mock -ModuleName Support -CommandName ConvertTo-Yaml { $args[0] }

$TestPath = New-Item -Path (Join-Path -Path "TestDrive:" -ChildPath "SampleConfig") -Name "CreateSampleConfigFolder" -ItemType Directory

[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'CMDArgs')]
$CMDArgs = @{
Description = "YAML configuration file with default description";
ProductNames = @("aad", "defender", "exo", "sharepoint", "teams");
M365Environment = "commercial";
OPAPath = ".";
LogIn = $true;
DisconnectOnExit = $false;
OutPath = '.';
AppID = '0';
CertificateThumbprint = '0';
Organization = '0';
OutFolderName = "M365BaselineConformance";
OutProviderFileName = "ProviderSettingsExport";
OutRegoFileName = "TestResults";
OutReportName = "BaselineReports";
ConfigLocation = $TestPath;
}
}
It 'Creates a sample configuration' {

{ New-Config @CMDArgs } | Should -Not -Throw

Test-Path -Path "$($TestPath)/SampleConfig.yaml" -PathType leaf | Should -Be $true
}
}

AfterAll {
Remove-Module Support -ErrorAction SilentlyContinue
}
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ Invoke-SCuBA -M365Environment gcc -ConfigFilePath minimal_config.yaml
```

**Typical Use** : config file `typical_config.yaml`
Typical use includes multiple products, specified as a list, and an M365 environment variable. Note that additional product values are commented out and will not be included, but are retained in the config file to easily add them back later.
Typical use includes multiple products, specified as a list, and an M365 environment variable. Note that additional product values are commented out and will not be included, but are retained in the config file to easily add them back later. ScubaGear's Support module also has functionality to generate an empty sample config file. Runnning the `New-Config` Cmdlet will generate a full sample config called `SampleConfig.yaml` that can be filled out based on the guidance below. Also parameters can be passed to the `New-Config` Cmdlet to change values inside the sample config.
```
Description: YAML Typical Config ( multiple products )
ProductNames:
Expand Down

0 comments on commit 9128a12

Please sign in to comment.