carlzxc71 / ORCA-automation

https://www.lindbergtech.com
MIT License
0 stars 0 forks source link

Introduction

Welcome to my first ever open-source project!

This project allows you to implement the required services and activate a system that will run your EOP configuration and match it with Microsofts best practice once a month.
The Microsoft Defender for Office 365 Recommended Configuration Analyzer (ORCA)

Why would you want this?

Why does the solution not use Azure Automation or Azure Functions instead of a VM

At the time of developing this solution the ExchangeOnlineManagement module had just announced their release of the -ManagedIdentity switch. The switch was limited to only work on Azure VM or Azure VM scaleset machines.

When trying to call this command with the switch locally you would just receive a timeout, same for Azure Functions.

The ORCA module has network-dependencies and uses the Resolve-DNSName commandlet. This is not allowed to run inside Azure Automation sandboxes, so we could not run the automation.ps1 script inside a Runbook.

There is one automation account used and that is to power on and off the virtual machine which in this case will simulate the Runbook sandbox VM.
The VM will be powered off at all times except for a few hours every month to keep costs down.

What does this solution do

  1. Triggers an Automation runbook on the 1st of each month to start an Azure VM
  2. The Azure VM has a scheduled task that runs on system startup that triggers a script
  3. The script authenticates to Exchange Online using the VM which has a Managed Identity & extracts the ORCA-report
  4. The report is emailed to your preferred destination
  5. Another runbook triggers to shutdown the virtual machine and deallocate it so you are not billed for VM uptime

We use Twilio Sendgrid Email API services because this is a service Microsoft has partnership with and you can configure a free subscription to their services directly in the Azure Portal.
This is what will allow us to send email in automated powershell-scripts.

Resources being configured:

Pre-requisites

Guide for implementation

1. Fork and clone this Git repository

Note that all the commands you will be instructed to execute will assume you are standing in the git-directory when executing them.

2. Authenticate and create your resource group that will host the Azure Resources

az login
az account list -o table
az account set -s "<Subscription Name>"

3. Run the template to automatically provision all the dependant Azure Resources

4. Register a SaaS-subscription for Twilio Sendgrid Email Platform

Microsoft recommends using Twilio for sending emails so we should be able to trust that they are a reliant partner. They even let you register for their services through the Azure Portal
Remember that you need a mailbox that you can access which will be used for the setup, example: automation@domain.com

Source-reference from MS Docs: Send an Email with Automation

Note: We use Single Sender Verification when performing the first-time setup, which is recommended for proof of concepts/test-setups.
After you have verified the entire setup for this solution you can look into Domain Verification

5. Create the keyvault secret and assign the VM managed identity Exchange Online Permissions

In this step you will store the API-key created in the previous step in the Keyvault you have deployed.
The script will use the keyvault to retreive the API-key for sending email and the VM requires Exchange Administrator to run the powershell commandlets Connect-ExchangeOnline & Invoke-ORCAReport

Connect-AzAccount #Login to Azure through Powershell

Convert the SendGrid API key into a SecureString

$Secret = ConvertTo-SecureString -String $SendGridAPIKey ` -AsPlainText -Force

Create the Keyvault Secret

Set-AzKeyVaultSecret -VaultName $VaultName -Name 'SendGridAPIKey' -SecretValue $Secret


The managed identity needs certain permissions in order to authenticate and query Exchange Online, we will use MS Graph for this

```Powershell
Connect-MgGraph -Scopes "User.Read.all","Application.Read.All","AppRoleAssignment.ReadWrite.All"
$params = @{
    ServicePrincipalId = '<Enter managed object ID of Virtual Machine>' # managed identity object id - you can find this under your resource group in the Azure Portal -> deployments -> vmDeployment -> outputs
    PrincipalId = '<Enter managed object ID of Virtual Machine>' # managed identity object id - you can find this under your resource group in the Azure Portal -> deployments -> vmDeployment -> outputs
    ResourceId = (Get-MgServicePrincipal -Filter "AppId eq '00000002-0000-0ff1-ce00-000000000000'").id # Exchange online
    AppRoleId = "dc50a0fb-09a3-484d-be87-e023b12c6440" # Exchange.ManageAsApp
}

New-MgServicePrincipalAppRoleAssignedTo @params

We also need to assign the Exchange Administrator role to the Managed Identity as only the application permissions are not supported.

It may take 10-15 minutes for all the permissions to propagate.

Note: In theory it should be enough with either the MS-graph permissions or the Exchange Admin role but at the time of developing this solution I have had issues where I did not complete both, this requirement may change later.

6. Login to the provisioned VM with RDP

In the future the aim is to deliver a solution that will not require this step, but for now we do.

<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Date>2022-10-25T08:03:23.4153238</Date>
    <Author>machine\admin</Author>
    <Description>Triggers and sends the automated ORCA report</Description>
    <URI>\Trigger-ORCAReport</URI>
  </RegistrationInfo>
  <Triggers>
    <BootTrigger>
      <Enabled>true</Enabled>
    </BootTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>S-1-5-21-2123838175-1840825630-523378789-500</UserId>
      <LogonType>Password</LogonType>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>false</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession>
    <UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>powershell.exe</Command>
      <Arguments>-ExecutionPolicy Bypass -File "C:\Automation\ORCA\Trigger-ORCAReport.ps1"</Arguments>
    </Exec>
  </Actions>
</Task>
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

Install-PackageProvider -Name NuGet -Confirm:$false -Force
Install-Module NuGet -Confirm:$false -Force

Install-Module ExchangeOnlineManagement -Confirm:$false -Force
Install-Module ORCA -Confirm:$false -Force
Install-Module Az -Confirm:$false -Force

7. Configure the deployed Automation Account to schedule VM start and stop

When you deployed all the Azure resources in step three you configured an Automation Account, this is what we will use to schedule the VM stop and start.

$ProgressPreference="silentlyContinue"

Disable-AzContextAutosave -Scope Process

Connect to Azure with system-assigned managed identity

$AzureContext = (Connect-AzAccount -Identity).context

set and store context

$AzureContext = Set-AzContext -SubscriptionName $AzureContext.Subscription -DefaultProfile $AzureContext

Stop the VM

Start-AzVM -ResourceGroupName $resourceGroupName -Name $vmName -Confirm:$false

- Choose **Save** then **Publish**
- Choose **Link to schedule**
  - Choose **Link a scheduled to your runbook**
  - Choose **Add a schedule**
  - Give it a name: **Start ORCA**
  - Starts: Chose the first of following month (We are assuming you will run this on the 1st of every month, you can adjust to fit you)
  - 8:00 AM for time
  - Set your Timezone
  - Chose **Recurring** -> **Recur every** 1 month
  - Chose **Month days** -> 1
  - Leave everything else as default and choose **Create**
- Choose **Parameters and run settings**
  - Change nothing and just choose **OK**
- Choose **OK**

- Go back to automation accounts and choose **Stop-VM**
  - Repeat the same steps and paste the following code
```Powershell
[CmdletBinding()]
param (
    [string] $vmName = "<Enter your VM name here>",
    [string] $resourceGroupName = "<Enter your RG here>"
)

$ProgressPreference="silentlyContinue"

Disable-AzContextAutosave -Scope Process

# Connect to Azure with system-assigned managed identity
$AzureContext = (Connect-AzAccount -Identity).context

# set and store context
$AzureContext = Set-AzContext -SubscriptionName $AzureContext.Subscription -DefaultProfile $AzureContext 

# Stop the VM
Stop-AzVM -ResourceGroupName $resourceGroupName -Name $vmName -Confirm:$false -Force

References & resources