Skip to content

Instantly share code, notes, and snippets.

@pkhabazi
Last active October 25, 2020 05:42
Show Gist options
  • Save pkhabazi/5d815820a689e7cddcebcd583366ee9c to your computer and use it in GitHub Desktop.
Save pkhabazi/5d815820a689e7cddcebcd583366ee9c to your computer and use it in GitHub Desktop.
Deploying and Managing Azure Sentinel – Ninja style
Describe "Azure Sentinel AlertRules Tests" {
$TestFiles = Get-ChildItem -Path .\SettingFiles\AlertRules.json -File -Recurse | ForEach-Object -Process {
@{
File = $_.FullName
ConvertedJson = (Get-Content -Path $_.FullName | ConvertFrom-Json)
Path = $_.DirectoryName
Name = $_.Name
}
}
It 'Converts from JSON | <File>' -TestCases $TestFiles {
param (
$File,
$ConvertedJson
)
$ConvertedJson | Should -Not -Be $null
}
It 'Schedueled rules have the minimum elements' -TestCases $TestFiles {
param (
$File,
$ConvertedJson
)
$expected_elements = @(
'displayName',
'description',
'severity',
'enabled',
'query',
'queryFrequency',
'queryPeriod',
'triggerOperator',
'triggerThreshold',
'suppressionDuration',
'suppressionEnabled',
'tactics',
'playbookName'
)
$rules = $ConvertedJson.Scheduled
$rules.ForEach{
$expected_elements | Should -BeIn $_.psobject.Properties.Name
}
}
It 'Fusion rules have the minimum elements' -TestCases $TestFiles {
param (
$File,
$ConvertedJson
)
$expected_elements = @(
'displayName',
'enabled',
'alertRuleTemplateName'
)
$rules = $ConvertedJson.Fusion
$rules.ForEach{
$expected_elements | Should -BeIn $_.psobject.Properties.Name
}
}
It 'MLBehaviorAnalytics rules have the minimum elements' -TestCases $TestFiles {
param (
$File,
$ConvertedJson
)
$expected_elements = @(
'displayName',
'enabled',
'alertRuleTemplateName'
)
$rules = $ConvertedJson.MLBehaviorAnalytics
$rules.ForEach{
$expected_elements | Should -BeIn $_.psobject.Properties.Name
}
}
It 'MicrosoftSecurityIncidentCreation rules have the minimum elements' -TestCases $TestFiles {
param (
$File,
$ConvertedJson
)
$expected_elements = @(
'displayName',
'enabled',
'description',
'productFilter',
'severitiesFilter',
'displayNamesFilter'
)
$rules = $ConvertedJson.MicrosoftSecurityIncidentCreation
$rules.ForEach{
$expected_elements | Should -BeIn $_.psobject.Properties.Name
}
}
}
# This is the main pipelien which covers all the stages
# The tasks are stored in pipelines/steps.yml
stages:
- stage: Dev
displayName: 'Deploying to Development environment'
jobs:
- template: pipelines/steps.yml
parameters:
environment: Dev
azureSubscription: ''
WorkspaceName: '' # Enter the Azure Sentinel Workspace name
SubscriptionId: 'cd466daa-3528-481e-83f1-7a7148706287'
ResourceGroupName: ''
ResourceGroupLocation: 'westeurope'
EnableSentinel: true
analyticsRulesFile: SettingFiles/AlertRules.json # leave empty if you dont want to configure Analytic rules
huntingRulesFile: SettingFiles/HuntingRules.json # leave empty if you dont want to configure Hunting rules
PlaybooksFolder: Playbooks/ # leave empty if you dont want to configure Playbooks
ConnectorsFile: SettingFiles/DataConnectors.json # leave empty if you dont want to configure Connectors
WorkbooksFolder: Workbooks/
WorkbookSourceId: '' # leave empty if you dont want to configure Workbook
- stage: Staging
displayName: 'Deploying to Acceptance environment'
condition: and(succeeded(), eq(variables['build.sourceBranch'], 'refs/heads/release'))
dependsOn: Dev # this stage runs after Dev
jobs:
- template: pipelines/steps.yml
parameters:
environment: Staging
azureSubscription: ''
WorkspaceName: '' # Enter the Azure Sentinel Workspace name
SubscriptionId: 'cd466daa-3528-481e-83f1-7a7148706287'
ResourceGroupName: ''
ResourceGroupLocation: 'westeurope'
EnableSentinel: true
analyticsRulesFile: SettingFiles/AlertRules.json # leave empty if you dont want to configure Analytic rules
huntingRulesFile: SettingFiles/HuntingRules.json # leave empty if you dont want to configure Hunting rules
PlaybooksFolder: Playbooks/ # leave empty if you dont want to configure Playbooks
ConnectorsFile: SettingFiles/DataConnectors.json # leave empty if you dont want to configure Connectors
WorkbooksFolder: Workbooks/
WorkbookSourceId: '' # leave empty if you dont want to configure Workbook
- stage: Production
displayName: 'Deploying to Production environment'
condition: and(succeeded(), eq(variables['build.sourceBranch'], 'refs/heads/master'))
dependsOn: Dev # this stage runs after Dev
jobs:
- template: pipelines/steps.yml
parameters:
environment: Production
azureSubscription: ''
WorkspaceName: '' # Enter the Azure Sentinel Workspace name
SubscriptionId: 'cd466daa-3528-481e-83f1-7a7148706287'
ResourceGroupName: ''
ResourceGroupLocation: 'westeurope'
EnableSentinel: true
analyticsRulesFile: SettingFiles/AlertRules.json # leave empty if you dont want to configure Analytic rules
huntingRulesFile: SettingFiles/HuntingRules.json # leave empty if you dont want to configure Hunting rules
PlaybooksFolder: Playbooks/ # leave empty if you dont want to configure Playbooks
ConnectorsFile: SettingFiles/DataConnectors.json # leave empty if you dont want to configure Connectors
WorkbooksFolder: Workbooks/
WorkbookSourceId: '' # leave empty if you dont want to configure Workbook
# Build Validation pipeline
# This Pipeline is used to trigger teh Pester test files when a PR is created
trigger: none
pool:
vmImage: 'ubuntu-latest'
steps:
- task: PowerShell@2
inputs:
targetType: 'inline'
script: 'Invoke-Pester *.tests.ps1 -OutputFile ./test-results.xml -OutputFormat NUnitXml'
errorActionPreference: 'continue'
pwsh: true
- task: PublishTestResults@2
inputs:
testResultsFormat: 'NUnit'
testResultsFiles: '**/test-results.xml'
failTaskOnFailedTests: true
# This is the Template that is used from the Main pipeline
# This template contains all the required steps
parameters:
- name: environment
displayName: environment name
type: string
- name: azureSubscription
displayName: Enter the Azure Serviceconntion
type: string
- name: SubscriptionId
displayName: Enter the Subscription id where the Azure sentinel workspace is deployed
type: string
- name: WorkspaceName
displayName: Enter the Azure Sentinel Workspace name
type: string
- name: EnableSentinel
displayName: Enable Azure Sentinel if not enabled
type: boolean
- name: analyticsRulesFile
displayName: path to Azure Sentinel Analytics ruile file
type: string
- name: huntingRulesFile
displayName: path to Azure Sentinel Hunting ruile file
type: string
- name: PlaybooksFolder
displayName: The path to the fodler with the playbook JSON files
type: string
- name: ConnectorsFile
displayName: The path to DataConnector json file
type: string
- name: WorkbooksFolder
displayName: The path to the folder which contains the Workbooks JSON files
type: string
- name: WorkbookSourceId
displayName: The id of resource instance to which the workbook will be associated
type: string
- name: ResourceGroupName
displayName: Enter the Resource group name for Playbooks and Workbooks
type: string
- name: ResourceGroupLocation
displayName: Enter the Resource group location for Playbooks and Workbooks
type: string
jobs:
- deployment: 'Sentinel'
displayName: DeploySentinelSolution
pool:
vmImage: 'ubuntu-latest'
environment: ${{ parameters.environment }}
strategy:
runOnce:
deploy:
steps:
- checkout: self
- task: PowerShell@2
displayName: 'Prepare environemnt'
inputs:
targetType: 'Inline'
script: |
Install-Module AzSentinel -Scope CurrentUser -Force
Import-Module AzSentinel
pwsh: true
- ${{ if eq(parameters.EnableSentinel, true) }}:
- task: AzurePowerShell@5
displayName: 'Enable and configure Azure Sentinel'
inputs:
azureSubscription: ${{ parameters.azureSubscription }}
ScriptType: 'InlineScript'
Inline: |
Set-AzSentinel -SubscriptionId ${{ parameters.SubscriptionId }} -WorkspaceName ${{ parameters.WorkspaceName }} -Confirm:$false
azurePowerShellVersion: 'LatestVersion'
pwsh: true
- ${{ if ne(parameters.PlaybooksFolder, '') }}:
- task: AzurePowerShell@4
displayName: 'Create and Update Playbooks'
inputs:
azureSubscription: ${{ parameters.azureSubscription }}
ScriptType: 'InlineScript'
Inline: |
$armTemplateFiles = Get-ChildItem -Path ${{ parameters.PlaybooksFolder }} -Filter *.json
$rg = Get-AzResourceGroup -ResourceGroupName ${{ parameters.ResourceGroupName }} -ErrorAction SilentlyContinue
if ($null -eq $rg) {
New-AzResourceGroup -ResourceGroupName ${{ parameters.ResourceGroupName }} -Location ${{ parameters.ResourceGroupLocation }}
}
foreach ($armTemplate in $armTemplateFiles) {
New-AzResourceGroupDeployment -ResourceGroupName ${{ parameters.ResourceGroupName }} -TemplateFile $armTemplate
}
azurePowerShellVersion: LatestVersion
pwsh: true
- ${{ if ne(parameters.analyticsRulesFile, '') }}:
- task: AzurePowerShell@5
displayName: 'Create and Update Alert Rules'
inputs:
azureSubscription: ${{ parameters.azureSubscription }}
ScriptType: 'InlineScript'
Inline: |
Import-AzSentinelAlertRule -SubscriptionId ${{ parameters.SubscriptionId }} -WorkspaceName ${{ parameters.WorkspaceName }} -SettingsFile ${{ parameters.analyticsRulesFile }}
azurePowerShellVersion: 'LatestVersion'
pwsh: true
- ${{ if ne(parameters.huntingRulesFile, '') }}:
- task: AzurePowerShell@5
displayName: 'Create and Update Hunting Rules'
inputs:
azureSubscription: ${{ parameters.azureSubscription }}
ScriptType: 'InlineScript'
Inline: |
Import-AzSentinelHuntingRule -SubscriptionId ${{ parameters.SubscriptionId }} -WorkspaceName ${{ parameters.WorkspaceName }} -SettingsFile ${{ parameters.huntingRulesFile }}
azurePowerShellVersion: 'LatestVersion'
pwsh: true
- ${{ if ne(parameters.ConnectorsFile, '') }}:
- task: AzurePowerShell@5
displayName: 'Create and Update Connectors'
inputs:
azureSubscription: ${{ parameters.azureSubscription }}
ScriptType: 'InlineScript'
Inline: |
Import-AzSentinelDataConnector -SubscriptionId ${{ parameters.SubscriptionId }} -Workspace ${{ parameters.WorkspaceName }} -SettingsFile ${{ parameters.ConnectorsFile }}
azurePowerShellVersion: LatestVersion
pwsh: true
- ${{ if ne(parameters.WorkbooksFolder, '')}}:
- task: AzurePowerShell@4
displayName: 'Create and Update Workbooks'
inputs:
azureSubscription: ${{ parameters.azureSubscription }}
ScriptType: 'InlineScript'
Inline: |
$armTemplateFiles = Get-ChildItem -Path ${{ parameters.WorkbooksFolder }} -Filter *.json
$rg = Get-AzResourceGroup -ResourceGroupName ${{ parameters.ResourceGroupName }} -ErrorAction SilentlyContinue
if ($null -eq $rg) {
New-AzResourceGroup -ResourceGroupName ${{ parameters.ResourceGroupName }} -Location ${{ parameters.ResourceGroupLocation }}
}
foreach ($armTemplate in $armTemplateFiles) {
New-AzResourceGroupDeployment -ResourceGroupName ${{ parameters.ResourceGroupName }} -TemplateFile $armTemplate -WorkbookSourceId ${{ parameters.WorkbookSourceId }}
}
azurePowerShellVersion: LatestVersion
pwsh: true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment