Skip to content

Latest commit

 

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

entra-zt-policy-engine

Zero Trust Conditional Access policy engine for Microsoft Entra ID. Audits an existing tenant against CIS Microsoft 365 Foundations Benchmark and Microsoft Zero Trust guidance, then deploys gap-closing policies via Terraform.

Note: Validated against a lab tenant seeded with intentional Conditional Access gaps (unblocked legacy authentication, missing MFA enforcement for admin roles, absent risk-based sign-in controls). Findings reflect that seeded environment, not a production tenant.

What This Does

Most CA-as-code repos deploy policies. This one audits first.

The audit engine (Python) connects to a live Entra ID tenant via Microsoft Graph, pulls all Conditional Access policies and named locations, and evaluates them against 10 Zero Trust baseline checks. It generates a markdown gap report showing what's passing, what's failing, and what needs attention.

The deploy engine (Terraform) provides a complete set of Zero Trust CA policies mapped to the same baseline checks. Policies deploy in report-only mode by default so you can verify behavior in sign-in logs before enforcing.

Baseline Checks

ID Check Reference
ZT-001 Block legacy authentication CIS M365 5.2.2.3
ZT-002 Require MFA for admin roles CIS M365 5.2.2.1
ZT-003 Require MFA for all users CIS M365 5.2.2.2
ZT-004 Sign-in risk policy configured CIS M365 5.2.2.6
ZT-005 User risk policy configured CIS M365 5.2.2.7
ZT-006 Location-based access controls CIS M365 5.2.2.8
ZT-007 Break-glass account exclusions MS Emergency Access guidance
ZT-008 Session controls configured CIS M365 5.2.2.4
ZT-009 Report-only policies flagged MS CA best practices
ZT-010 Disabled policies flagged MS CA best practices

Sample Output

Every audit run produces a markdown gap report and an HTML report in sample-output/.

Audit report

Full HTML: sample-output/gap_report.html

Before vs After Deployment

Before and after comparison

Full HTML: before · after · comparison

Project Structure

entra-zt-policy-engine/
├── audit/
│   ├── audit.py              # main entry point
│   ├── graph_client.py       # Graph API auth + data pull
│   ├── baseline.py           # zero trust baseline checks
│   ├── report.py             # markdown report generator
│   └── requirements.txt      # Python dependencies
├── deploy/
│   ├── providers.tf          # AzureAD provider config
│   ├── variables.tf          # input variables
│   ├── main.tf               # all CA policy resources
│   ├── outputs.tf            # deployment outputs
│   └── terraform.tfvars.example  # template for user config
├── sample-output/
│   ├── before_report.md      # audit before deployment
│   ├── after_report.md       # audit after deployment
│   └── gap_report.md         # latest audit report
└── README.md

Prerequisites

  • Python 3.9+
  • Terraform 1.5+
  • Azure CLI (az login)
  • An Entra ID tenant with P1 or P2 licensing (required for Conditional Access)
  • Account with Security Reader role (audit) or Conditional Access Administrator role (deploy)

Usage

Audit

Run the audit to see your tenant's current Zero Trust posture:

# Clone the repo
git clone https://github.com/Dfrank77/entra-zt-policy-engine.git
cd entra-zt-policy-engine

# Set up Python environment
python3 -m venv venv
source venv/bin/activate
pip install -r audit/requirements.txt

# Authenticate to your tenant
az login

# Run the audit
cd audit
python audit.py

The audit generates a gap report at sample-output/gap_report.md.

Deploy

Close the gaps identified by the audit:

cd deploy

# Configure your environment
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars with your break-glass IDs, admin group ID, etc.

# Deploy
terraform init
terraform plan
terraform apply

Policies deploy in report-only mode by default. Monitor sign-in logs to verify behavior, then change policy_state to "enabled" in terraform.tfvars and run terraform apply again.

Compare two audits

Save the audit results as JSON before and after making changes, then generate a side-by-side comparison:

Re-audit

After deploying, run the audit again to confirm the gaps are closed:

cd ../audit
python audit.py

Deployed Policies

ID Policy What It Does
ZT-001 Block Legacy Authentication Blocks Exchange ActiveSync and other legacy auth clients that cannot perform MFA
ZT-002 Require MFA for Admins Requires MFA for the specified admin group
ZT-003 Require MFA for All Users Baseline MFA requirement for every user in the tenant
ZT-004 Require MFA for Risky Sign-ins Triggers MFA on medium and high risk sign-ins detected by Identity Protection
ZT-005 Require Password Change for User Risk Forces password change and MFA when a user account is flagged as high risk
ZT-006 Block High-Risk Country Sign-ins Blocks sign-ins from specified countries and unknown locations
ZT-008 Enforce Session Sign-in Frequency Forces re-authentication after a configurable number of hours and disables persistent browser sessions

All policies exclude break-glass accounts to prevent tenant lockout.

References

Author

Darius Frank — IAM & Cloud Security

License

MIT

About

Zero Trust Conditional Access policy engine for Microsoft Entra ID. Audits existing policies against CIS benchmarks and deploys gap-closing policies via Terraform.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages