- PowerShell 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Add-POP3Account.ps1 and Audit-POP3Isolation.ps1 now read tenant domain, tenant ID, and legacy app/group identifiers from config.psd1 via Import-PowerShellDataFile. config.example.psd1 is the committed template. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
| .gitignore | ||
| Add-POP3Account.ps1 | ||
| Audit-POP3Isolation.ps1 | ||
| config.example.psd1 | ||
| mailboxes.example.txt | ||
| README.md | ||
POP3 Mailbox Isolation for Amtelco
Scripts for giving each Amtelco POP3 client mailbox its own Entra ID app registration and an Exchange Online application access policy, so no app can read any mailbox except its own.
How the isolation works
Each mailbox gets three things:
| Piece | Where it lives | Purpose |
|---|---|---|
App registration (POP3-<name>) |
Entra ID (Azure Portal) | Identity the POP3 client authenticates as. Holds the client ID and secret. |
Mail-enabled security group (POP3-<name>) |
Exchange Online | Contains exactly one member: the mailbox. |
| Application access policy | Exchange Online | RestrictAccess scoping the app ID to that group only. |
Because every app is restricted to a group containing only its own mailbox, a compromised client ID and
secret can only ever reach that one mailbox. The audit script proves this by testing every app against
every mailbox and expecting Denied everywhere except the diagonal.
Files
| File | Purpose |
|---|---|
Add-POP3Account.ps1 |
Add a single new mailbox (group + policy + verification). Day-to-day script. |
Audit-POP3Isolation.ps1 |
Full audit. Produces an HTML report and CSVs in a timestamped POP3-Audit-* folder. |
config.psd1 |
Tenant domain, tenant ID, and legacy app/group identifiers. Git-ignored. |
config.example.psd1 |
Template for config.psd1. |
mailboxes.txt |
List of mailboxes the audit checks. One per line. Git-ignored. |
mailboxes.example.txt |
Template for mailboxes.txt. |
Prerequisites
- PowerShell 5.1 or later.
- The
ExchangeOnlineManagementmodule:Install-Module ExchangeOnlineManagement -Scope CurrentUser - An account with Exchange Administrator rights.
- Rights to create app registrations and grant admin consent in Entra ID.
First-time setup after cloning
Copy-Item config.example.psd1 config.psd1
Copy-Item mailboxes.example.txt mailboxes.txt
Then edit config.psd1 with your tenant's values and mailboxes.txt with the real mailbox addresses,
one per line. Both scripts refuse to run until config.psd1 exists.
Adding a new mailbox
1. Create the mailbox in Exchange Online
Create it in the Microsoft 365 admin center (or with New-Mailbox) and confirm it has a license and a
primary SMTP address. The scripts do not create the mailbox.
2. Create a dedicated app registration in Entra ID
Every client gets its own app. This is what makes the isolation work.
- Entra ID > App registrations > New registration.
- Name it
POP3-<clientname>. Single tenant. No redirect URI. - API permissions > Add a permission > APIs my organization uses > search Office 365 Exchange Online > Application permissions > tick POP.AccessAsApp.
- Click Grant admin consent for the tenant.
- Certificates & secrets > New client secret. Copy the Value column immediately (not the Secret ID). It is only shown once.
- From Overview, copy the Application (client) ID.
3. Run the add script
.\Add-POP3Account.ps1 -Email "newclient@yourdomain.com" -ClientId "<client id from step 2>"
You will be prompted to sign in to Exchange Online. The script then:
- Creates a mail-enabled security group
POP3-<name>containing only that mailbox. - Creates an application access policy restricting the app ID to that group.
- Tests the policy against the new mailbox and against one other existing mailbox.
Expected result: Granted on its own mailbox, Denied on the other one.
4. Wait if the result is PENDING
Policies can take up to 30 minutes to propagate. Re-check with:
Test-ApplicationAccessPolicy -Identity "newclient@yourdomain.com" -AppId "<client id>"
5. Configure the POP3 client in Amtelco
You need the client ID, the secret value from step 2, the mailbox address, and the tenant ID.
The tenant ID is printed at the end of the add script (it comes from config.psd1).
6. Add the mailbox to the audit list
Append the new address to mailboxes.txt on its own line. Without this the account will not appear in
the next audit report.
7. Run the audit
.\Audit-POP3Isolation.ps1
This regenerates the HTML report and the cross-reference matrix that proves every app is denied on every mailbox except its own. The report opens automatically when complete. Output folders are git-ignored.
Removing a mailbox
- Delete the app registration in Entra ID (this revokes the secret immediately).
- Remove the policy and group in Exchange Online:
Get-ApplicationAccessPolicy | Where-Object { $_.AppId -eq "<client id>" } | Remove-ApplicationAccessPolicy -Confirm:$false
Remove-DistributionGroup -Identity "POP3-<name>" -Confirm:$false
- Remove the address from
mailboxes.txt.
Notes
- Tenant domain and tenant ID come from
config.psd1. The add script also accepts-TenantDomainto override the configured domain for a single run. - Client secrets are never stored in this repo. Keep them in Amtelco's config and your password manager only.
- The legacy shared app policy is left in place pointed at a
POP3-Disabledgroup as a safety net. Its app registration has been deleted.