Skip to content

Add AppLocker IaC project template #185

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
34 changes: 34 additions & 0 deletions templates/AppLockerProject/.github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

on:
push:
branches:
- main

jobs:
publish:

runs-on: windows-latest

steps:
- uses: actions/checkout@v1
- name: Install Prerequisites
run: .\build\prerequisites.ps1 -BuildWorker -DependencyPath (Join-Path $env:GITHUB_WORKSPACE build\requiredModules.psd1)
shell: powershell
- name: Validate Configuration Data
run: .\build\validate.ps1 -TestType ConfigurationData -DependencyPath (Join-Path $env:GITHUB_WORKSPACE build\requiredModules.psd1) -ProjectRoot $env:GITHUB_WORKSPACE
shell: powershell
- name: Build
run: .\build\build.ps1 -IncludeRsop -DependencyPath (Join-Path $env:GITHUB_WORKSPACE build\requiredModules.psd1) -SourcePath (Join-Path $env:GITHUB_WORKSPACE configurationdata) -OutputPath (Join-Path $env:GITHUB_WORKSPACE output)
shell: powershell
- uses: actions/upload-artifact@v3
with:
name: build-artifacts
path: |
.\output\rsop
.\output\policies
- name: Publish
run: .\build\publish.ps1
shell: powershell
- name: Validate Integration Tests
run: .\build\validate.ps1 -TestType Integration -DependencyPath (Join-Path $env:GITHUB_WORKSPACE build\requiredModules.psd1) -ProjectRoot $env:GITHUB_WORKSPACE
shell: powershell
24 changes: 24 additions & 0 deletions templates/AppLockerProject/.github/workflows/validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
on: [pull_request]

jobs:
validate:

runs-on: windows-latest

steps:
- uses: actions/checkout@v1
- name: Install Prerequisites
run: .\build\prerequisites.ps1 -BuildWorker -DependencyPath (Join-Path $env:GITHUB_WORKSPACE build\requiredModules.psd1)
shell: powershell
- name: Validate Configuration Data
run: .\build\validate.ps1 -TestType ConfigurationData -DependencyPath (Join-Path $env:GITHUB_WORKSPACE build\requiredModules.psd1) -ProjectRoot $env:GITHUB_WORKSPACE
shell: powershell
- name: Build
run: .\build\build.ps1 -IncludeRsop -DependencyPath (Join-Path $env:GITHUB_WORKSPACE build\requiredModules.psd1) -SourcePath (Join-Path $env:GITHUB_WORKSPACE configurationdata) -OutputPath (Join-Path $env:GITHUB_WORKSPACE output)
shell: powershell
- uses: actions/upload-artifact@v3
with:
name: build-artifacts
path: |
.\output\rsop
.\output\policies
2 changes: 2 additions & 0 deletions templates/AppLockerProject/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
output
testresults.xml
5 changes: 5 additions & 0 deletions templates/AppLockerProject/PSMDInvoke.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
param (
$Path
)

New-PSMDTemplate -ReferencePath "$PSScriptRoot" -OutPath $Path
11 changes: 11 additions & 0 deletions templates/AppLockerProject/PSMDTemplate.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@{
TemplateName = 'AppLockerProject'
Version = "1.0.0"
AutoIncrementVersion = $true
Tags = 'module','psframework', 'applocker'
Author = 'Jan-Hendrik Peters'
Description = 'PowerShell Framework based AppLocker CI template'
Exclusions = @("PSMDInvoke.ps1", ".PSMDDependency") # Contains list of files - relative path to root - to ignore when building the template
Scripts = @{ }
NoFolder = $true
}
91 changes: 91 additions & 0 deletions templates/AppLockerProject/azurepipelines.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
trigger:
branches:
include:
- main

jobs:
- job: Build
displayName: 'Build AppLocker Artifacts'
pool:
name: Default
steps:
- task: PowerShell@2
name: prereq
displayName: 'Download prerequisites'
inputs:
filePath: '.\build\prerequisites.ps1'
arguments: '-DependencyPath (Join-Path $(Build.SourcesDirectory) build\requiredModules.psd1)'
- task: PowerShell@2
name: validateyaml
displayName: Validate Configuration Data
inputs:
filePath: '.\build\validate.ps1'
arguments: '-TestType ConfigurationData -DependencyPath (Join-Path $(Build.SourcesDirectory) build\requiredModules.psd1) -ProjectRoot $(Build.SourcesDirectory)'
- task: PowerShell@2
name: buildpolicy
displayName: Build policy XML
inputs:
filePath: '.\build\build.ps1'
arguments: '-IncludeRsop -DependencyPath (Join-Path $(Build.SourcesDirectory) build\requiredModules.psd1) -SourcePath (Join-Path $(Build.SourcesDirectory) configurationdata) -OutputPath (Join-Path $(Build.SourcesDirectory) output)'
- task: PublishBuildArtifacts@1
displayName: 'Publish Policy XML Files'
inputs:
PathtoPublish: 'output/Policies'
ArtifactName: Policies
- task: PublishBuildArtifacts@1
displayName: 'Publish Policy RSOP Files'
inputs:
PathtoPublish: 'output/Rsop'
ArtifactName: Rsop
- task: PublishTestResults@2
displayName: 'Publish Configuration Data Test Results'
condition: succeededOrFailed()
inputs:
testResultsFormat: 'NUnit'
testResultsFiles: 'tests/testresults.xml'
mergeTestResults: true
failTaskOnFailedTests: true
testRunTitle: 'Configuration Data Tests'
- deployment: Prod
dependsOn: Build
displayName: Prod Deployment
environment: Prod
pool:
name: Default
strategy:
runOnce:
deploy:
steps:
- task: DownloadBuildArtifacts@0
displayName: 'Download Build Artifact: Rsop'
inputs:
buildType: 'current'
artifactName: Rsop
downloadPath: $(Build.SourcesDirectory)
- task: DownloadBuildArtifacts@0
displayName: 'Download Build Artifact: Policies'
inputs:
buildType: 'current'
artifactName: Policies
downloadPath: $(Build.SourcesDirectory)
- task: PowerShell@2
name: publishpolicies
displayName: Publish policies
inputs:
filePath: '.\build\publish.ps1'
arguments: '-DependencyPath (Join-Path $(Build.SourcesDirectory) build\requiredModules.psd1) -SourcePath (Join-Path $(Build.SourcesDirectory) configurationdata) -OutputPath (Join-Path $(Build.SourcesDirectory) output)'
- task: PowerShell@2
name: validateintegration
displayName: Validate Integration
inputs:
filePath: '.\build\validate.ps1'
arguments: '-TestType Integration -DependencyPath (Join-Path $(Build.SourcesDirectory) build\requiredModules.psd1) -ProjectRoot $(Build.SourcesDirectory)'
- task: PublishTestResults@2
displayName: 'Publish Integration Test Results'
condition: succeededOrFailed()
inputs:
testResultsFormat: 'NUnit'
testResultsFiles: 'tests/testresults.xml'
mergeTestResults: true
failTaskOnFailedTests: true
testRunTitle: 'Integration Tests'
70 changes: 70 additions & 0 deletions templates/AppLockerProject/build/build.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@

param
(
[string]
$DependencyPath = (Resolve-Path "$PSScriptRoot\requiredModules.psd1").Path,

[string]
$SourcePath = "$PSScriptRoot\..\configurationdata",

[string]
$OutputPath = "$PSScriptRoot\..\output",

[switch]
$IncludeRsop
)

$psdependConfig = Import-PowerShellDataFile -Path $DependencyPath
$modPath = Resolve-Path -Path $psdependConfig.PSDependOptions.Target
$modOld = $env:PSModulePath
$pathSeparator = [System.IO.Path]::PathSeparator
$env:PSModulePath = "$modPath$pathSeparator$modOld"

$SourcePath = Resolve-Path -Path $SourcePath -ErrorAction Stop
$OutputPath = if (-not (Resolve-Path -Path $OutputPath -ErrorAction SilentlyContinue))
{
(New-Item -Path $OutputPath -ItemType Directory -Force).FullName
}
else
{
Resolve-Path -Path $OutputPath
}

$rsopPath = Join-Path -Path $OutputPath -ChildPath rsop
$policyPath = Join-Path -Path $OutputPath -ChildPath policies
if (-not (Test-Path -Path $rsopPath))
{
$null = New-Item -Path $rsopPath -ItemType Directory -Force
}

if (-not (Test-Path -Path $policyPath))
{
$null = New-Item -Path $policyPath -ItemType Directory -Force
}

if (Get-DatumRsopCache)
{
Clear-DatumRsopCache
}

$datum = New-DatumStructure -DefinitionFile (Join-Path $SourcePath Datum.yml)
$rsops = Get-DatumRsop $datum (Get-DatumNodesRecursive -AllDatumNodes $Datum.AllNodes)
$rsops | Export-AlfXml -Path $policyPath

if (-not $IncludeRsop)
{
$env:PSModulePath = $modOld
return
}

foreach ($rsop in $rsops)
{
$domainPath = Join-Path -Path $rsopPath -ChildPath $rsop.Domain
if (-not (Test-Path -Path $domainPath))
{
$null = New-Item -Path $domainPath -ItemType Directory -Force
}
$rsop | ConvertTo-Yaml -OutFile (Join-Path -Path $domainPath -ChildPath "$($rsop.PolicyName).yml") -Force
}

$env:PSModulePath = $modOld
28 changes: 28 additions & 0 deletions templates/AppLockerProject/build/prerequisites.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
param
(
[string]
$DependencyPath = (Resolve-Path "$PSScriptRoot\requiredModules.psd1").Path,

[switch]
$BuildWorker
)

$psdependConfig = Import-PowerShellDataFile -Path $DependencyPath

if ($BuildWorker.IsPresent)
{
$null = Get-PackageProvider -Name NuGet -ForceBootstrap

Install-Module -Force -Name PackageManagement, PowerShellGet -Repository $psdependConfig.PSDependOptions.Parameters.Repository -Scope CurrentUser

Remove-Module -Name PowerShellGet -ErrorAction SilentlyContinue -Force
Remove-Module -Name PackageManagement -ErrorAction SilentlyContinue -Force
Import-Module -Force -Name PowerShellGet
Import-Module -Force -Name PackageManagement

$null = Install-WindowsFeature -Name GPMC
}

Save-Module -Name PSDepend -Repository $psdependConfig.PSDependOptions.Parameters.Repository -Path $psdependConfig.PSDependOptions.Target -Force
Import-Module -Name (Join-Path -Path $psdependConfig.PSDependOptions.Target -ChildPath PSDepend\*\PSDepend.psd1 -Resolve)
Invoke-PSDepend -Path $DependencyPath -Force
63 changes: 63 additions & 0 deletions templates/AppLockerProject/build/publish.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
param
(
[string]
$DependencyPath = (Resolve-Path "$PSScriptRoot\requiredModules.psd1").Path,

[string]
$OutputPath = (Resolve-Path "$PSScriptRoot\..\output").Path,

[string]
$SourcePath = "$PSScriptRoot\..\configurationdata"
)

$psdependConfig = Import-PowerShellDataFile -Path $DependencyPath
$modPath = Resolve-Path -Path $psdependConfig.PSDependOptions.Target
$modOld = $env:PSModulePath
$pathSeparator = [System.IO.Path]::PathSeparator
$env:PSModulePath = "$modPath$pathSeparator$modOld"
$datum = New-DatumStructure -DefinitionFile (Join-Path $SourcePath Datum.yml)
[hashtable[]] $rsops = Get-DatumRsop $datum (Get-DatumNodesRecursive -AllDatumNodes $Datum.AllNodes)

foreach ($policy in (Get-ChildItem -Path (Join-Path -Path $OutputPath -ChildPath Policies) -Recurse -Filter *.xml))
{
$searcher = [adsisearcher]::new()
$searcher.Filter = "(&(objectClass=groupPolicyContainer)(displayName=$($policy.BaseName)))"
$policyFound = $searcher.FindOne()

if (-not $policyFound)
{
$null = New-GPO -Name $policy.BaseName -Comment "Auto-updated applocker policy" -Domain $policy.Directory.Name
}

$rsop = $rsops | Where-Object { $_['PolicyName'] -eq $policy.BaseName }
foreach ($link in $rsop.Links)
{
$param = @{
Name = $rsop.PolicyName
Target = $link.OrgUnitDn
Domain = $policy.Directory.Name
Confirm = $false
}

if ($rsop.ContainsKey('Enabled'))
{
$param['LinkEnabled'] = $link.Enabled
}
if ($rsop.ContainsKey('Enforced'))
{
$param['Enforced'] = $link.Enforced
}
if ($rsop.ContainsKey('Order'))
{
$param['Order'] = $link.Order
}

Set-GPLink @param
}

$policyFound = $searcher.FindOne()

Set-AppLockerPolicy -XmlPolicy $policy.FullName -Ldap $policyFound.Path
}

$env:PSModulePath = $modOld
18 changes: 18 additions & 0 deletions templates/AppLockerProject/build/requiredModules.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@{
PSDependOptions = @{
AddToPath = $false
Target = 'output\RequiredModules'
Parameters = @{
Repository = 'PSGallery'
AllowPreRelease = $true
}
}

'powershell-yaml' = '0.4.7'
PSScriptAnalyzer = '1.21.0'
Pester = '5.4.1'
'Sampler.DscPipeline' = '0.2.0-preview0015' # Unfortunately still in preview
Datum = '0.40.1'
'Datum.InvokeCommand' = '0.3.0'
AppLockerFoundry = '1.1.5'
}
37 changes: 37 additions & 0 deletions templates/AppLockerProject/build/validate.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[CmdletBinding()]
param
(
[string]
$DependencyPath = (Resolve-Path "$PSScriptRoot\requiredModules.psd1").Path,

[string]
$ProjectRoot = (Resolve-Path "$PSScriptRoot\..").Path,

[ValidateSet('Unit', 'ConfigurationData', 'Integration')]
[string]
$TestType
)

$psdependConfig = Import-PowerShellDataFile -Path $DependencyPath
$modPath = Resolve-Path -Path $psdependConfig.PSDependOptions.Target
$modOld = $env:PSModulePath
$pathSeparator = [System.IO.Path]::PathSeparator
$env:PSModulePath = "$modPath$pathSeparator$modOld"

Import-Module Pester -Force -ErrorAction Stop -MinimumVersion 5.0.0

$global:testroot = Join-Path $ProjectRoot tests
$po = [PesterConfiguration]::New()
$po.Run.Path = Join-Path $global:testroot $TestType
$po.Run.PassThru = $true
$po.Output.Verbosity = 'Detailed'
$po.TestResult.Enabled = $true
$po.TestResult.OutputPath = Join-Path $global:testroot 'testresults.xml'
$po.TestResult.OutputFormat = 'NUnit2.5'

$result = Invoke-Pester -Configuration $po
$env:PSModulePath = $modOld

if ($result.FailedCount -gt 0) {
throw "Pester tests failed"
}
Loading