Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement MS.AAD.3.1v1 phishing resistant mfa for all users #433

Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
70f6a73
Structural baseline updates (cleaned up) (#334)
ahuynhMITRE May 15, 2023
49b95c7
Initial drop of secure baseline automation (#336)
crutchfield May 25, 2023
b82249a
Add quiet mode for invoke-scuba (#357)
crutchfield Jun 2, 2023
825861d
Invert Stance on Defender Preset Policies in Markdown (#355)
adhilto Jun 7, 2023
2c950f0
Substantiative changes to Sharepoint Baseline minus Rationale (#360)
Sloane4 Jun 7, 2023
f7a6e75
Fix test location file path (#367)
schrolla Jun 8, 2023
5ad473b
Enhanced smoke test - check for missing results (#356)
crutchfield Jun 13, 2023
d423116
One drive baseline (#370)
Dylan-MITRE Jun 16, 2023
99081e7
DLP policy group additions and updates (#381)
schrolla Jun 26, 2023
b023ecb
Adjudicate Substantive AAD Baseline Comments (#379)
ssatyapal123 Jun 29, 2023
4572307
Added SharePoint to MS.DEFENDER.4.2v1 locations (#402)
schrolla Jun 30, 2023
a04eb7b
Update aad scubagear code to align to revised baseline (#408)
Sloane4 Jul 3, 2023
2ade0e4
Differentiate policy id vs implementation (#414)
crutchfield Jul 5, 2023
38ea3ea
WIP
Jul 11, 2023
27e3958
Updated ReportDetails on tests to match patch results (#426)
schrolla Jul 11, 2023
3a029ae
Address Power Platform pilot comments and substantive changes in the …
buidav Jul 11, 2023
7f3822d
wip
Jul 13, 2023
fbdf897
Implemented AAD 3.1
Jul 13, 2023
f9b3398
WIP
Jul 11, 2023
24decbb
wip
Jul 13, 2023
d7cbbf7
Implemented AAD 3.1
Jul 13, 2023
f39411f
Update Rego/AADConfig.rego
crutchfield Jul 13, 2023
e6d68cb
Update Smoke Test to handle CAP (#418)
crutchfield Jul 13, 2023
f73e96c
update MS.AAD.7.6v1 to only check for global admin (#428)
adhilto Jul 13, 2023
d195e00
Merge branch '351-implement-new-scubagear-rego-check-for-msaad31v1-ph…
Jul 14, 2023
34037da
Combine Sharepoint with OneDrive and address feedback from review per…
tkol2022 Jul 14, 2023
fa9c0b6
Adjudicate review comments
Jul 14, 2023
6e1ad9a
Merge branch 'emerald' into 351-implement-new-scubagear-rego-check-fo…
crutchfield Jul 14, 2023
cc764c0
WIP
Jul 11, 2023
18862f8
wip
Jul 13, 2023
07a4cbe
Implemented AAD 3.1
Jul 13, 2023
98f35a9
WIP
Jul 11, 2023
b243639
wip
Jul 13, 2023
39e0536
Update Rego/AADConfig.rego
crutchfield Jul 13, 2023
3f34b60
Adjudicate review comments
Jul 14, 2023
86a6cde
Merge branch '351-implement-new-scubagear-rego-check-for-msaad31v1-ph…
Jul 17, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/run_markdown_check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
on:
workflow_dispatch:
pull_request:
types: [opened, reopened]
branches:
- "main"
pull_request_review:
types: [submitted]
push:
branches:
- "main"
- "*Baseline*"
paths:
- "baselines/*.md"

name: Markdown Check

jobs:
Run-Markdown-Check:
runs-on: windows-latest
defaults:
run:
shell: powershell
permissions:
contents: read
steps:
- name: Checkout repo code
uses: actions/checkout@v3
- name: Execute markdown checks
run: |
$PSVersionTable
Invoke-Pester Testing\Unit\PowerShell\CreateReport -Output Detailed
4 changes: 3 additions & 1 deletion .github/workflows/run_opa_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ on:
push:
paths:
- "**.rego"
- "**/run_opa_tests.yaml"
pull_request:
types: [opened, reopened]
branches:
- "main"
- "emerald" #TODO: Remove after emerald release
paths:
- "**.rego"
pull_request_review:
Expand All @@ -31,4 +33,4 @@ jobs:
run: opa check Rego Testing/Unit/Rego --strict

- name: Run OPA Tests
run: opa test Rego/*.rego Testing/Unit/Rego/**/*.rego -v
run: opa test Rego/*.rego Rego/Utils/*.rego Testing/Unit/Rego/**/*.rego -v
86 changes: 0 additions & 86 deletions PowerShell/ScubaGear/Modules/CreateReport/BaselineTitles.json

This file was deleted.

209 changes: 164 additions & 45 deletions PowerShell/ScubaGear/Modules/CreateReport/CreateReport.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,17 @@ function New-Report {
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[switch]
$DarkMode
$DarkMode,

[Parameter(Mandatory=$true)]
[ValidateNotNull()]
[object]
$SecureBaselines
)

$FileName = Join-Path -Path $PSScriptRoot -ChildPath "BaselineTitles.json"
$AllTitles = Get-Content $FileName | ConvertFrom-Json
$Titles = $AllTitles.$BaselineName
$ScubaGitHubUrl = "https://github.com/cisagov/ScubaGear"

$ProductSecureBaseline = $SecureBaselines.$BaselineName

$FileName = Join-Path -Path $OutPath -ChildPath "$($OutProviderFileName).json"
$SettingsExport = Get-Content $FileName | ConvertFrom-Json
Expand All @@ -71,7 +76,7 @@ function New-Report {
}

$MetaDataTable = $MetaData | ConvertTo-HTML -Fragment
$MetaDataTable = $MetaDataTable -replace '^(.*?)<table>','<table style = "text-align:center;">'
$MetaDataTable = $MetaDataTable -replace '^(.*?)<table>','<table id="tenant-data" style = "text-align:center;">'
$Fragments += $MetaDataTable
$ReportSummary = @{
"Warnings" = 0;
Expand All @@ -82,52 +87,72 @@ function New-Report {
"Date" = $SettingsExport.date;
}

foreach ($Title in $Titles) {
foreach ($BaselineGroup in $ProductSecureBaseline) {
$Fragment = @()
foreach ($test in $TestResults | Where-Object -Property Control -eq $Title.Number) {
$MissingCommands = @()

if ($SettingsExport."$($BaselineName)_successful_commands" -or $SettingsExport."$($BaselineName)_unsuccessful_commands") {
# If neither of these keys are present, it means the provider for that baseline
# hasn't been updated to the updated error handling method. This check
# here ensures backwards compatibility until all providers are udpated.
$MissingCommands = $test.Commandlet | Where-Object {$SettingsExport."$($BaselineName)_successful_commands" -notcontains $_}
}

if ($MissingCommands.Count -gt 0) {
$Result = "Error"
$ReportSummary.Errors += 1
$MissingString = $MissingCommands -Join ", "
$test.ReportDetails = "This test depends on the following command(s) which did not execute successfully: $($MissingString). See terminal output for more details."
}
elseif ($test.RequirementMet) {
$Result = "Pass"
$ReportSummary.Passes += 1
}
elseif ($test.Criticality -eq "Should") {
$Result = "Warning"
$ReportSummary.Warnings += 1
}
elseif ($test.Criticality.EndsWith('3rd Party') -or $test.Criticality.EndsWith('Not-Implemented')) {
$Result = "N/A"
$ReportSummary.Manual += 1
foreach ($Control in $BaselineGroup.Controls){

$Test = $TestResults | Where-Object -Property PolicyId -eq $Control.Id

if ($null -ne $Test){
$MissingCommands = @()

if ($SettingsExport."$($BaselineName)_successful_commands" -or $SettingsExport."$($BaselineName)_unsuccessful_commands") {
# If neither of these keys are present, it means the provider for that baseline
# hasn't been updated to the updated error handling method. This check
# here ensures backwards compatibility until all providers are udpated.
$MissingCommands = $Test.Commandlet | Where-Object {$SettingsExport."$($BaselineName)_successful_commands" -notcontains $_}
}

if ($MissingCommands.Count -gt 0) {
$Result = "Error"
$ReportSummary.Errors += 1
$MissingString = $MissingCommands -Join ", "
$Test.ReportDetails = "This test depends on the following command(s) which did not execute successfully: $($MissingString). See terminal output for more details."
}
elseif ($Test.RequirementMet) {
$Result = "Pass"
$ReportSummary.Passes += 1
}
elseif ($Test.Criticality -eq "Should") {
$Result = "Warning"
$ReportSummary.Warnings += 1
}
elseif ($Test.Criticality.EndsWith('3rd Party') -or $test.Criticality.EndsWith('Not-Implemented')) {
$Result = "N/A"
$ReportSummary.Manual += 1
}
else {
$Result = "Fail"
$ReportSummary.Failures += 1
}

$Fragment += [pscustomobject]@{
"Control ID"=$Control.Id
"Requirement"=$Control.Value
"Result"= if ($Control.Deleted) {"-"} else {$Result}
"Criticality"=if ($Control.Deleted) {"-"} else {$Test.Criticality}
"Details"=if ($Control.Deleted) {"-"} else {$Test.ReportDetails}
}
}
else {
$Result = "Fail"
$ReportSummary.Failures += 1
$ReportSummary.Errors += 1
$Fragment += [pscustomobject]@{
"Control ID"=$Control.Id
"Requirement"=$Control.Value
"Result"= "Error - Test results missing"
"Criticality"= "-"
"Details"= "Report issue on <a href=`"$ScubaGitHubUrl/issues`" target=`"_blank`">GitHub</a>"
}
Write-Warning -Message "WARNING: No test results found for Control Id $($Control.Id)"
}

$Fragment += [pscustomobject]@{
"Requirement"=$test.Requirement;
"Result"=$Result;
"Criticality"=$test.Criticality;
"Details"=$test.ReportDetails}
}

$Number = $Title.Number
$Name = $Title.Title
$Fragments += $Fragment | ConvertTo-Html -PreContent "<h2>$Number $Name</h2>" -Fragment

$Number = $BaselineName.ToUpper() + '-' + $BaselineGroup.GroupNumber
$Name = $BaselineGroup.GroupName
$GroupAnchor = New-MarkdownAnchor -GroupNumber $BaselineGroup.GroupNumber -GroupName $BaselineGroup.GroupName
$MarkdownLink = "<a class='control_group' href=`"$($ScubaGitHubUrl)/blob/$($SettingsExport.module_version)/baselines/$($BaselineName.ToLower()).md#$GroupAnchor`" target=`"_blank`">$Name</a>"
$Fragments += $Fragment | ConvertTo-Html -PreContent "<h2>$Number $MarkdownLink</h2>" -Fragment
}

$Title = "$($FullName) Baseline Report"
Expand Down Expand Up @@ -177,6 +202,100 @@ function New-Report {
$ReportSummary
}

function Import-SecureBaseline{
<#
.Description
This function parses the secure baseline via each product markdown document to align policy with the
software baseline.
.Functionality
Internal
#>
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[ValidateScript({Test-Path -PathType Container $_})]
[string]
$BaselinePath = (Join-Path -Path $PSScriptRoot -ChildPath "..\..\..\..\baselines\")
)

$ProductNames = Get-ChildItem $BaselinePath -Filter "*.md" | ForEach-Object {$_.Name.SubString(0, $_.Name.Length - 3)}
$Output = @{}

foreach ($Product in $ProductNames) {
$Output[$Product] = @()
$ProductPath = Join-Path -Path $BaselinePath -ChildPath "$Product.md"
$MdLines = Get-Content -Path $ProductPath

# Select-String line numbers aren't 0-indexed, hence the "-1" on the next line
$LineNumbers = Select-String "^## [0-9]+\." "$($BaselinePath)$($Product).md" | ForEach-Object {$_."LineNumber"-1}
$Groups = $LineNumbers | ForEach-Object {$MdLines[$_]}

foreach ($GroupName in $Groups) {
$Group = @{}
$Group.GroupNumber = $GroupName.Split(".")[0].SubString(3) # 3 to remove the "## "
$Group.GroupName = $GroupName.Split(".")[1].Trim() # 1 to remove the leading space
$Group.Controls = @()

$IdRegex = "#### MS\.[$($Product.ToUpper())]+\.$($Group.GroupNumber)\.\d+v\d+\s*$"
# Select-String line numbers aren't 0-indexed, hence the "-1" on the next line
$LineNumbers = Select-String $IdRegex "$($BaselinePath)$($Product).md" | ForEach-Object {$_."LineNumber"-1}

foreach ($LineNumber in $LineNumbers) {
# This assumes that the value is on the immediate next line after the ID and ends in a period.
$LineAdvance = 1;
$Value = ([string]$MdLines[$LineNumber+$LineAdvance]).Trim()

while ($Value.Substring($Value.Length-1,1) -ne "."){
$LineAdvance++
$Value += ' ' + ([string]$MdLines[$LineNumber+$LineAdvance]).Trim()
}

$Value = [System.Net.WebUtility]::HtmlEncode($Value)
$Id = [string]$MdLines[$LineNumber].Substring(5)

if ($Id.EndsWith("X")){
$Deleted = $true
$Id = $Id -Replace ".$"
$Value = "[DELETED] " + $Value
}
else {
$Deleted = $false
}

$Group.Controls += @{"Id"=$Id; "Value"=$Value; "Deleted"=$Deleted}
}

$Output[$Product] += $Group
}
}

$Output
}

function New-MarkdownAnchor{
param (
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]
$GroupNumber,
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]
$GroupName
)
[Int32]$OutNumber = $null

if ($true -eq [Int32]::TryParse($GroupNumber, [ref]$OutNumber)){
$MangledName = $GroupName.ToLower().Trim().Replace(' ', '-')
return "#$($GroupNumber.Trim())-$MangledName"
}
else {
$InvalidGroupNumber = New-Object System.ArgumentException "$GroupNumber is not valid"
throw $InvalidGroupNumber
}
}

Export-ModuleMember -Function @(
'New-Report'
'New-Report',
'Import-SecureBaseline'
)
Loading