@AlexMags
So I DevSecOpsed
Office 365
@alexmags #winops
@AlexMags
Alex Magnay
Twitter: @alexmags
Email: alex@alexmags.com
linkedin.com/in/amagnay
@AlexMags
This talk
• Unconventional use of Release Pipelines
• Office 365 configuration as versioned code
• Releasing changes through environments to prod
• Testing Office 365 configuration compliance
• NIST CyberSecurity Framework
@AlexMags
MS-500 Microsoft 365 Security Administration
Scenario:
Contoso Group (CG) is a financial services organisation.
Contoso is splitting off it’s investment banking division as
a new company named Fabrikam Ltd
Contoso Group has 70,000 users, Fabrikam has 7000
users.
Objective:
Prepare new foundational IT services for Fabrikam to
operate independently of Contoso.
Adopt a cloud first approach.
@AlexMags
So much to configure!!!
• AAD tenant config
• AAD Privliged Identity Management
• AAD Conditional Access
• Office 365 Groups policies
• Exchange spam policies
• Exchange anti phish policies
• Exchange Malware filter policy
• Exchange safe attachments policies
• Exchange safe links policies
• Exchange org config
• Exchange Authentication policies
• Exchange DKIM and antispoofing
• Exchange role-based access
• Exchange Transport Rules
• Exchange connector TLS policies
• Exchange Data loss prevention policies
• Sensitive information types
• Office 365 audit log alerts
• Data Retention policies
• SharePoint tenant config
• SharePoint DLP policies
• SharePoint role-based access
• Teams messaging policies
• Teams meeting policies
• Teams client policies
• Teams federation
• Teams role-based access
• Etc….
• Etc….
• Etc….
@AlexMags
@AlexMags
What’s included?
@AlexMags
What’s included?
https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/configuration-analyzer-for-security-policies
@AlexMags
https://www.youtube.com/watch?v=6mFk3Oxdiwc
@AlexMags
@AlexMags
@AlexMags
Environments & Licensing
@AlexMags
@AlexMags
Azure
Subscriptions
Accounts
Departments
EA Portal Enterprise
Agreement
Fabricam
IT
Lab Test Production
Research
Grid
Contoso
IT
Production
@AlexMags
Subscriptions
AAD Identity
Accounts
Invoicing
EA Portal Enterprise
Agreement
Fabricam
IT
Lab
domain
Azure Lab
O365 Lab
(MPSA)
Test
domain
Azure Test
O365 Test
(MPSA)
Production
domain
Azure Prod
O365
Production
Azure
DevOps
Research
Grid
Contoso
IT
Production
@AlexMags
Configuration as code
@AlexMags
@AlexMags
@AlexMags
@AlexMags
@AlexMags
@AlexMags
@AlexMags
Release config to environments
@AlexMags
Read tenant config and set stuff
$TenantSettingsJson = get-content 'ExchangeAuthenticationPolicies.json' | ConvertFrom-Json
Foreach ($policy in $TenantSettingsJson)
{
Write-Output "Applying Exchange authentication policies for: $($policy.identity)"
# build hashtable of switches for PowerShell splatting
$HashArguments = @{
AllowBasicAuthActiveSync = $policy.AllowBasicAuthActiveSync
AllowBasicAuthAutodiscover =$policy.AllowBasicAuthAutodiscover
AllowBasicAuthImap = $policy.AllowBasicAuthImap
AllowBasicAuthMapi = $policy.AllowBasicAuthMapi
AllowBasicAuthOfflineAddressBook = $policy.AllowBasicAuthOfflineAddressBook
AllowBasicAuthOutlookService = $policy.AllowBasicAuthOutlookService
AllowBasicAuthPop = $policy.AllowBasicAuthPop
AllowBasicAuthReportingWebServices = $policy.AllowBasicAuthReportingWebServices
AllowBasicAuthRpc =$policy.AllowBasicAuthRpc
AllowBasicAuthSmtp = $policy.AllowBasicAuthSmtp
AllowBasicAuthWebServices = $policy.AllowBasicAuthWebServices
AllowBasicAuthPowershell = $policy.AllowBasicAuthPowershell
}
# Test if policy if exists and update it. Otherwise create new policy
If (Get-AuthenticationPolicy -Identity $policy.name -ErrorAction SilentlyContinue)
{
Set-AuthenticationPolicy -Identity $policy.name @HashArguments -Verbose
}
else # create new policy
{
New-AuthenticationPolicy -name $policy.Name @HashArguments -Verbose
}
}
1. Create object from JSON
2. Loop though policies in JSON object
3. Build hash table of command
switches based on object properties
4a. Execute set command with
switches
or
4b. Execute new command with
switches
@AlexMags
Release approvals
• Approvals to individual or team
• Approve & defer to change time
• Approval Policies
• Can’t approve own releases
• Require additional MFA check
• Release gates
• Check ServiceNow change approval
@AlexMags
Log messages are captured
@AlexMags
Compliance as code
@AlexMags
@AlexMags
@AlexMags
@AlexMags
Lab tenant config exported to JSON
# Export Exchange auth policies
Get-AuthenticationPolicy `
| ConvertTo-Json -Depth 10 `
| Out-File "ExchangeAuthenticationPolicies.json"
@AlexMags
@AlexMags
Testing with Pester
https://github.com/pester
Describe 'Notepad’ {
It 'Exists in Windows folder’ {
'C:Windowsnotepad.exe' | Should -Exist
}
}
Describing Notepad
[+] Exists in Windows folder 4ms
@AlexMags
Testing with Pester
https://github.com/pester
Describe 'Notepad’ {
It 'Exists in Windows folder’ {
'C:WindowsNotAtAllPad.exe' | Should -Exist `
-because "law 57 of Windows builds"
}
}
Describing Notepad
[-] Exists in Windows folder 17ms
Expected path 'C:WindowsNotAtAllPad.exe' to exist,
because law 57 of Windows builds, but it did not exist.
@AlexMags
Test tenant config compared to JSON
$TenantSettingsJson = get-content $genericJSONPath | ConvertFrom-Json
$currentCompanyConfig = Get-AzureADMSGroupLifecyclePolicy -ErrorAction SilentlyContinue
# Note "-because" parameters requires Pester module v4
Describe "Office365 group lifecycle policy for $($AADtenant.DisplayName)" {
it "Office 365 group lifecycle policy" {
$currentCompanyConfig | should -not -BeNullOrEmpty `
-Because "Office 365 group lifecycle policy ensures projects are closed down and data archived"
}
it "Office 365 Group lifetime" {
$currentCompanyConfig.GroupLifetimeInDays | should -be $TenantSettingsJson.GroupLifetimeInDays `
-Because "Unused o365 groups should be archived after $($TenantSettingsJson.GroupLifetimeInDays)"
}
it "Office 365 group notification mails" {
$currentCompanyConfig.AlternateNotificationEmails | should -be $TenantSettingsJson.AlternateNotificationEmails `
-Because "$($TenantSettingsJson.AlternateNotificationEmails) should be notified of unused o365 groups"
}
}
Read JSON, get current config
Assert that current config shouldn’t be blank/unset
Assert that current config should match JSON
@AlexMags
@AlexMags
@AlexMags
@AlexMags
@AlexMags
Incident tickets in ServiceNow
• Email to special email address
• ServiceNow email flow rule based on TO: address
• Email becomes incident in correct assignment group
• Azure DevOps notification rule logic:
Only email on 1st failure after a success
@AlexMags
The good
• Misconfigurations detected quickly
• Microsoft feature changes detected
• Can demonstrate IT are in control
@AlexMags
The good, the bad
• Requires frequent maintenance to keep up with
organisation changes
• Requires frequent maintenance to keep up with Microsoft
changes/new features
• Maintenance requires PowerShell & DevOps skills
@AlexMags
The good, the bad, the ugly
• Outsourced operations teams don’t have PowerShell
automation skills
“we’re administrators not developers!”
@AlexMags
The future?
• Continuous assessment of SaaS configuration with
SaaS Security Posture Management (SSPM)

So I DevSecOpsed Office 365

  • 1.
    @AlexMags So I DevSecOpsed Office365 @alexmags #winops
  • 2.
    @AlexMags Alex Magnay Twitter: @alexmags Email:alex@alexmags.com linkedin.com/in/amagnay
  • 3.
    @AlexMags This talk • Unconventionaluse of Release Pipelines • Office 365 configuration as versioned code • Releasing changes through environments to prod • Testing Office 365 configuration compliance • NIST CyberSecurity Framework
  • 4.
    @AlexMags MS-500 Microsoft 365Security Administration Scenario: Contoso Group (CG) is a financial services organisation. Contoso is splitting off it’s investment banking division as a new company named Fabrikam Ltd Contoso Group has 70,000 users, Fabrikam has 7000 users. Objective: Prepare new foundational IT services for Fabrikam to operate independently of Contoso. Adopt a cloud first approach.
  • 5.
    @AlexMags So much toconfigure!!! • AAD tenant config • AAD Privliged Identity Management • AAD Conditional Access • Office 365 Groups policies • Exchange spam policies • Exchange anti phish policies • Exchange Malware filter policy • Exchange safe attachments policies • Exchange safe links policies • Exchange org config • Exchange Authentication policies • Exchange DKIM and antispoofing • Exchange role-based access • Exchange Transport Rules • Exchange connector TLS policies • Exchange Data loss prevention policies • Sensitive information types • Office 365 audit log alerts • Data Retention policies • SharePoint tenant config • SharePoint DLP policies • SharePoint role-based access • Teams messaging policies • Teams meeting policies • Teams client policies • Teams federation • Teams role-based access • Etc…. • Etc…. • Etc….
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
    @AlexMags Subscriptions AAD Identity Accounts Invoicing EA PortalEnterprise Agreement Fabricam IT Lab domain Azure Lab O365 Lab (MPSA) Test domain Azure Test O365 Test (MPSA) Production domain Azure Prod O365 Production Azure DevOps Research Grid Contoso IT Production
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
    @AlexMags Read tenant configand set stuff $TenantSettingsJson = get-content 'ExchangeAuthenticationPolicies.json' | ConvertFrom-Json Foreach ($policy in $TenantSettingsJson) { Write-Output "Applying Exchange authentication policies for: $($policy.identity)" # build hashtable of switches for PowerShell splatting $HashArguments = @{ AllowBasicAuthActiveSync = $policy.AllowBasicAuthActiveSync AllowBasicAuthAutodiscover =$policy.AllowBasicAuthAutodiscover AllowBasicAuthImap = $policy.AllowBasicAuthImap AllowBasicAuthMapi = $policy.AllowBasicAuthMapi AllowBasicAuthOfflineAddressBook = $policy.AllowBasicAuthOfflineAddressBook AllowBasicAuthOutlookService = $policy.AllowBasicAuthOutlookService AllowBasicAuthPop = $policy.AllowBasicAuthPop AllowBasicAuthReportingWebServices = $policy.AllowBasicAuthReportingWebServices AllowBasicAuthRpc =$policy.AllowBasicAuthRpc AllowBasicAuthSmtp = $policy.AllowBasicAuthSmtp AllowBasicAuthWebServices = $policy.AllowBasicAuthWebServices AllowBasicAuthPowershell = $policy.AllowBasicAuthPowershell } # Test if policy if exists and update it. Otherwise create new policy If (Get-AuthenticationPolicy -Identity $policy.name -ErrorAction SilentlyContinue) { Set-AuthenticationPolicy -Identity $policy.name @HashArguments -Verbose } else # create new policy { New-AuthenticationPolicy -name $policy.Name @HashArguments -Verbose } } 1. Create object from JSON 2. Loop though policies in JSON object 3. Build hash table of command switches based on object properties 4a. Execute set command with switches or 4b. Execute new command with switches
  • 25.
    @AlexMags Release approvals • Approvalsto individual or team • Approve & defer to change time • Approval Policies • Can’t approve own releases • Require additional MFA check • Release gates • Check ServiceNow change approval
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
    @AlexMags Lab tenant configexported to JSON # Export Exchange auth policies Get-AuthenticationPolicy ` | ConvertTo-Json -Depth 10 ` | Out-File "ExchangeAuthenticationPolicies.json"
  • 32.
  • 33.
    @AlexMags Testing with Pester https://github.com/pester Describe'Notepad’ { It 'Exists in Windows folder’ { 'C:Windowsnotepad.exe' | Should -Exist } } Describing Notepad [+] Exists in Windows folder 4ms
  • 34.
    @AlexMags Testing with Pester https://github.com/pester Describe'Notepad’ { It 'Exists in Windows folder’ { 'C:WindowsNotAtAllPad.exe' | Should -Exist ` -because "law 57 of Windows builds" } } Describing Notepad [-] Exists in Windows folder 17ms Expected path 'C:WindowsNotAtAllPad.exe' to exist, because law 57 of Windows builds, but it did not exist.
  • 35.
    @AlexMags Test tenant configcompared to JSON $TenantSettingsJson = get-content $genericJSONPath | ConvertFrom-Json $currentCompanyConfig = Get-AzureADMSGroupLifecyclePolicy -ErrorAction SilentlyContinue # Note "-because" parameters requires Pester module v4 Describe "Office365 group lifecycle policy for $($AADtenant.DisplayName)" { it "Office 365 group lifecycle policy" { $currentCompanyConfig | should -not -BeNullOrEmpty ` -Because "Office 365 group lifecycle policy ensures projects are closed down and data archived" } it "Office 365 Group lifetime" { $currentCompanyConfig.GroupLifetimeInDays | should -be $TenantSettingsJson.GroupLifetimeInDays ` -Because "Unused o365 groups should be archived after $($TenantSettingsJson.GroupLifetimeInDays)" } it "Office 365 group notification mails" { $currentCompanyConfig.AlternateNotificationEmails | should -be $TenantSettingsJson.AlternateNotificationEmails ` -Because "$($TenantSettingsJson.AlternateNotificationEmails) should be notified of unused o365 groups" } } Read JSON, get current config Assert that current config shouldn’t be blank/unset Assert that current config should match JSON
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
    @AlexMags Incident tickets inServiceNow • Email to special email address • ServiceNow email flow rule based on TO: address • Email becomes incident in correct assignment group • Azure DevOps notification rule logic: Only email on 1st failure after a success
  • 41.
    @AlexMags The good • Misconfigurationsdetected quickly • Microsoft feature changes detected • Can demonstrate IT are in control
  • 42.
    @AlexMags The good, thebad • Requires frequent maintenance to keep up with organisation changes • Requires frequent maintenance to keep up with Microsoft changes/new features • Maintenance requires PowerShell & DevOps skills
  • 43.
    @AlexMags The good, thebad, the ugly • Outsourced operations teams don’t have PowerShell automation skills “we’re administrators not developers!”
  • 44.
    @AlexMags The future? • Continuousassessment of SaaS configuration with SaaS Security Posture Management (SSPM)

Editor's Notes

  • #3 Background infrastructure engineering teams investment banking, asset management High availability, high security, regulatory compliance. Come off Office365 deployment. Sprinked DevOps on it
  • #4 On prem vs IaaS Terrafrom Why youre here. WHAT it is Terraform workflow HOW to use it Demo Terraform for Dev, Sec, and Ops News Warning: Fetish for excruciating PowerPoint transitions.
  • #5 Green field. Whole stack. New domain. New tenant
  • #6 All the configuration needs to be tracked, maintained
  • #7 Office365 Security Portal
  • #8 Graph API you can export this list of improvement actions and see if any flipped from completed to not completed?
  • #9 Graph API you can export this list of improvement actions and see if any flipped from completed to not completed?
  • #10 Most accessible intro to release pipelines. Esp OPS guys
  • #12 When you’ve been configuring Conditional Access by hand, and locked yourself and the entire company out, you know it. http://www.jklossner.com/humannature
  • #14 EA (250 users minimum) MPSA (points, # users vary on E3 or E5)
  • #16 LOGICALLY
  • #18 Admins subject to CA policy
  • #19 VSTS Packer
  • #20 Vault for your project
  • #21 Azure DevOps scheduler
  • #22 The account provided gives the code context Onmicrosoft.com
  • #24 Additional approval required to deploy prod
  • #27 Additional approval required to deploy prod
  • #30 PESTER
  • #33 Config exported to JSON
  • #34 Assert things that should be true and you want to know if they’re not
  • #35 Assert things that should be true and you want to know if they’re not
  • #37 Test current config compared to JSON