Zero Trust Policy Implementation - From Open Source to Enterprise
Conditional Access Policy Lab with Two Implementation Tiers
Conditional Access is the foundation of Zero Trust security. Learn to implement it in both open-source (free) and enterprise (Azure) environments.
Self-Hosted Open Source
*M365 Developer Program
| Scenario | Best Tier | Why |
|---|---|---|
| Personal learning / Home lab | Tier 1 | Free, learn fundamentals |
| Startup / Small business | Tier 1 | Cost-effective, full control |
| Job interviews / Portfolio | Tier 2 | Enterprise experience expected |
| Enterprise consulting | Tier 2 | Fortune 500 use Microsoft |
| Hybrid/multi-cloud | Both | Different tools, same concepts |
| Phase | Tier 1 (Authentik) | Tier 2 (Entra ID) |
|---|---|---|
| Core Concepts | 30 min | 30 min |
| Environment Setup | 60 min (if Project A done) | 45 min |
| Basic Policies (5) | 60 min | 60 min |
| Advanced Policies (5) | 90 min | 90 min |
| Testing & Validation | 45 min | 45 min |
| Total | 4.5 hours | 4.5 hours |
Understanding Conditional Access fundamentals
Whether using Authentik or Entra ID, you're implementing the same Zero Trust principles
Conditional Access is an if-then policy engine that makes access decisions based on signals:
These are the inputs your policy evaluates:
| Signal | Description | Examples |
|---|---|---|
| User/Group | Who is trying to access? | All users, Admins, Guests |
| Application | What are they accessing? | Email, HR Portal, Admin Console |
| Location | Where are they coming from? | IP address, Country, Network |
| Device | What device are they using? | Managed, BYOD, OS type |
| Risk Level | How risky is this sign-in? | Anonymous IP, Impossible travel |
| Client App | What protocol is used? | Browser, Mobile app, Legacy auth |
These are the enforcement actions your policy can take:
| Action | Description | When to Use |
|---|---|---|
| Block | Deny access completely | High-risk locations, Legacy auth |
| Require MFA | Force multi-factor authentication | Untrusted networks, Sensitive apps |
| Require Compliant Device | Device must meet security standards | Corporate data access |
| Session Controls | Limit what users can do | Download restrictions, timeout |
| Allow | Grant access (default if no block) | Trusted conditions met |
If ANY policy says "Block", access is denied - even if other policies say "Allow". This is called most restrictive wins.
Order of evaluation:
Free, self-hosted conditional access
Requires: Project A (Authentik SSO) completed • Docker • Linux server
| Policy Type | Purpose | Complexity |
|---|---|---|
| Expression Policy | Python code for custom logic | Advanced |
| Reputation Policy | Block based on IP reputation score | Easy |
| Password Policy | Enforce password complexity | Easy |
| Event Matcher Policy | Trigger on specific events | Medium |
| GeoIP Policy | Block/allow by country | Medium |
Block access from countries where your organization has no presence:
# ============================================
# POLICY: Block Access from High-Risk Countries
# Name: geo-block-countries
# ============================================
# List of blocked country codes (ISO 3166-1 alpha-2)
# Add/remove countries based on your threat model
BLOCKED_COUNTRIES = [
"RU", # Russia
"CN", # China
"KP", # North Korea
"IR", # Iran
]
# Get the GeoIP data from the request context
# Authentik automatically enriches requests with GeoIP
geo_data = request.context.get("geoip", {})
country_code = geo_data.get("country", "")
# Log the access attempt for audit
ak_logger.info(
f"GeoIP check: User {request.user} from {country_code}"
)
# Return False to DENY access, True to ALLOW
if country_code in BLOCKED_COUNTRIES:
ak_message("Access denied: Your location is restricted")
return False
return True
GeoIP requires the MaxMind database. Add to your docker-compose.yml:
AUTHENTIK_GEOIP=/geoip/GeoLite2-City.mmdb
# ============================================
# POLICY: Require MFA for Admin Users
# Name: require-mfa-admins
# ============================================
# Check if user is in the admins group
admin_groups = ["authentik Admins", "IT-Admins"]
user_groups = [g.name for g in request.user.ak_groups.all()]
# Check if user is admin
is_admin = any(g in admin_groups for g in user_groups)
if not is_admin:
# Not an admin, policy doesn't apply
return True
# Admin user - check if MFA is configured
mfa_devices = request.user.mfa_devices.filter(confirmed=True)
if not mfa_devices.exists():
ak_message(
"Administrators must configure MFA before accessing this application"
)
return False
return True
# ============================================
# POLICY: Block Outdated/Insecure Browsers
# Name: block-legacy-browsers
# ============================================
import re
# Get User-Agent from request
user_agent = request.http_request.META.get("HTTP_USER_AGENT", "")
# Patterns for blocked browsers
BLOCKED_PATTERNS = [
r"MSIE [0-9]", # Internet Explorer
r"Trident/", # IE 11
r"Chrome/[0-6][0-9]\.", # Chrome < 70
r"Firefox/[0-5][0-9]\.", # Firefox < 60
]
for pattern in BLOCKED_PATTERNS:
if re.search(pattern, user_agent):
ak_message(
"Your browser is outdated. Please update to continue."
)
ak_logger.warning(
f"Blocked legacy browser: {user_agent}"
)
return False
return True
Use Authentik's built-in Reputation Policy:
| Name | block-bad-reputation |
| Check IP | ✅ Enabled |
| Check Username | ✅ Enabled |
| Threshold | -5 (block if score below) |
Failed logins decrease reputation score. Successful logins increase it. IPs with low scores are blocked.
Apply your policies to specific applications:
Enterprise-grade Microsoft cloud policies
Requires: Microsoft 365 Developer Program (free) or Azure AD P1/P2 license
Critical security baseline - Block IMAP, POP3, SMTP, and other legacy protocols:
| Setting | Value |
|---|---|
| Name | CA001: Block Legacy Authentication |
| Users → Include | All users |
| Users → Exclude | Break-glass accounts (emergency) |
| Target resources | All cloud apps |
| Conditions → Client apps | ☑️ Exchange ActiveSync clients ☑️ Other clients |
| Grant | 🚫 Block access |
| Enable policy | Report-only (test first!) |
Create 2 emergency admin accounts BEFORE enabling block policies. These accounts should be excluded from ALL policies and use physical security keys.
| Setting | Value |
|---|---|
| Name | CA002: Require MFA - All Users |
| Users → Include | All users |
| Users → Exclude | Break-glass accounts, Service accounts |
| Target resources | All cloud apps |
| Conditions | (none - always applies) |
| Grant | ✅ Require multi-factor authentication |
Step 1: Create a Named Location first:
Step 2: Create the policy:
| Setting | Value |
|---|---|
| Name | CA003: Block Foreign Access |
| Users | All users |
| Target resources | All cloud apps |
| Conditions → Locations | Include: Any location Exclude: Allowed Countries |
| Grant | 🚫 Block access |
Use Identity Protection to block risky sign-ins (requires P2):
| Setting | Value |
|---|---|
| Name | CA004: Block High-Risk Sign-ins |
| Users | All users |
| Target resources | All cloud apps |
| Conditions → Sign-in risk | ☑️ High |
| Grant | 🚫 Block access |
Microsoft AI detects: Anonymous IP addresses, impossible travel, malware-linked IPs, password spray attacks, unfamiliar sign-in properties.
| Setting | Value |
|---|---|
| Name | CA005: Require Compliant Device - HR Apps |
| Users | All users |
| Target resources → Select apps | HR Portal, Finance App |
| Grant | ✅ Require device to be marked as compliant |
Device compliance requires Microsoft Intune enrollment. In a lab, you can test with Windows devices joined to your Entra ID tenant.
Side-by-side feature comparison
The skills transfer between platforms - learn one, understand both
| Feature | Tier 1: Authentik | Tier 2: Entra ID |
|---|---|---|
| Cost | $0 (self-hosted) | Free tier / $6-$9/user/mo |
| GeoIP Blocking | ✅ Expression Policy | ✅ Named Locations |
| IP Blocking | ✅ Expression Policy | ✅ Named Locations |
| Require MFA | ✅ Flow stages | ✅ Grant controls |
| Device Compliance | ⚠️ Limited (user-agent) | ✅ Intune integration |
| Risk-Based Policies | ✅ Reputation scoring | ✅ Identity Protection AI |
| Block Legacy Auth | ✅ Expression Policy | ✅ Client app condition |
| Session Controls | ✅ Flow configuration | ✅ Session controls |
| Custom Logic | ✅ Python (full flexibility) | ⚠️ Limited (fixed conditions) |
| Report-Only Mode | ⚠️ Manual logging | ✅ Built-in |
| Policy Templates | ❌ Build from scratch | ✅ Security defaults templates |
| Concept | Authentik Term | Entra ID Term |
|---|---|---|
| Policy container | Policy Binding | Conditional Access Policy |
| Custom logic | Expression Policy | Custom Controls (limited) |
| Location-based | GeoIP in Expression | Named Locations |
| Rate limiting | Reputation Policy | Sign-in frequency |
| MFA enforcement | MFA Validation Stage | Grant: Require MFA |
| Application assignment | Policy Binding to App | Target Resources |
Validate your policies work correctly
Always test policies in Report-Only mode before enforcing
| Tool | Purpose | Platform |
|---|---|---|
| VPN Services | Test geo-blocking from different countries | Both |
| Browser DevTools | Modify User-Agent for browser testing | Both |
| Authentik Audit Logs | View policy evaluation details | Tier 1 |
| Entra Sign-in Logs | View CA policy results | Tier 2 |
| What If Tool | Simulate policy evaluation | Tier 2 |
Navigate to: Protection → Conditional Access → What If
This lets you simulate a sign-in and see which policies would apply without actually signing in!
Enterprise skills you've learned
| Interview Question | Your Answer |
|---|---|
| "How would you implement Zero Trust?" | Conditional Access policies that verify signals (user, device, location, risk) before granting access. Never trust by default. |
| "What's your approach to blocking legacy auth?" | Create policy targeting "Other clients" client app condition, block all, exclude break-glass accounts. Test in report-only first. |
| "How do you handle risky sign-ins?" | Identity Protection detects risk signals. High risk = block. Medium risk = require MFA. Combine with impossible travel detection. |
| "Experience with policy engines?" | Both enterprise (Entra ID Conditional Access) and open-source (Authentik Expression Policies). Same concepts, different implementations. |
| Project | How It Connects |
|---|---|
| Project A: Zero-Trust SSO | Foundation for Tier 1 - Authentik setup |
| Project I: Hybrid Identity | Extends Tier 2 with on-prem AD integration |
| Project J: Multi-Region Entra ID | Advanced Tier 2 with PIM and Access Reviews |