Bridge On-Premises Active Directory with Cloud Identity
Understanding Hybrid Identity Architecture
Connect your on-premises Active Directory to cloud applications. Users login once with their AD credentials and access everything - on-prem AND cloud!
This project teaches Hybrid Identity concepts used in:
| Enterprise Solution | Our Implementation | Skill Transfer |
|---|---|---|
| Azure AD Connect | Authentik LDAP Provider | 90% |
| AD FS (Federation Services) | Authentik SAML/OIDC | 85% |
| Okta AD Agent | LDAP Source Integration | 90% |
| Ping Identity AD Connector | Directory Synchronization | 85% |
| Password Hash Sync (PHS) | LDAP Bind Authentication | 80% |
Without Hybrid Identity:
With Hybrid Identity: One password, one identity, one audit trail - everywhere!
| Phase | Time | Difficulty |
|---|---|---|
| Understanding Concepts | 20-30 min | Reading |
| Samba AD DC Setup | 45-60 min | Medium |
| AD Users & Groups | 20-30 min | Easy |
| LDAP Source Configuration | 30-45 min | Medium |
| SSO Federation Setup | 30-45 min | Medium |
| Testing & Validation | 30-45 min | Easy |
Total: 4-5 hours
Understanding Hybrid Identity Architecture
Hybrid Identity bridges the gap between on-premises and cloud identity systems
| Model | How It Works | We'll Build |
|---|---|---|
| Password Hash Sync (PHS) | Hash of password copied to cloud | ❌ |
| Pass-Through Auth (PTA) | Cloud validates against on-prem AD live | ✅ |
| Federation (AD FS) | On-prem issues tokens, cloud trusts them | ✅ |
| Directory Sync Only | Users synced, separate passwords | ✅ |
LDAP (Lightweight Directory Access Protocol) is how systems talk to directories like Active Directory.
LDAP is how you search and read a giant phone book of users. Active Directory speaks LDAP, and so does Authentik - they can talk to each other!
| LDAP Term | Meaning | Example |
|---|---|---|
| DN | Distinguished Name (unique path) | CN=John,OU=Users,DC=corp,DC=local |
| DC | Domain Component | DC=corp,DC=local |
| OU | Organizational Unit | OU=Engineering |
| CN | Common Name | CN=John Smith |
| Bind | Authenticate to LDAP | Login with username/password |
For this lab, we use Samba AD DC instead of Windows Server:
What you need before starting
This project builds on Project A (Authentik SSO)
You must have a working Authentik installation from Project A:
| Resource | Additional Need | Total with Project A |
|---|---|---|
| RAM | +2 GB | 10 GB recommended |
| Storage | +10 GB | 110 GB recommended |
| CPU | Same | 4+ cores |
LDAP should NOT be exposed to the internet. Keep ports 389/636 on your internal network only!
Before starting, decide on your AD domain name:
| Setting | Example | Your Value |
|---|---|---|
| AD Domain Name | corp.local | __________________ |
| NetBIOS Name | CORP | __________________ |
| Admin Password | (secure password) | __________________ |
For home labs, use a .local domain like corp.local. In production, you'd use a real domain subdomain like ad.yourcompany.com.
Setting up your on-premises Active Directory
SSH into your server from Project A. All commands run on the same server as Authentik.
# Navigate to your projects folder
cd ~
# Create directory for Samba AD
mkdir -p samba-ad/config samba-ad/data
# Navigate into it
cd samba-ad
# Verify structure
ls -la
# Should show: config/ data/
Create the Docker Compose configuration for Samba AD:
# ============================================
# SAMBA ACTIVE DIRECTORY DOMAIN CONTROLLER
# This creates a full AD DC in Docker
# ============================================
version: "3.8"
services:
# ============================================
# SAMBA AD DC
# Full Active Directory Domain Controller
# ============================================
samba-ad:
image: nowsci/samba-domain
container_name: samba-ad
hostname: dc1
# Privileged mode required for AD to work properly
privileged: true
restart: unless-stopped
# Environment variables configure the AD domain
environment:
# Your AD domain name (e.g., corp.local)
- DOMAIN=corp.local
# NetBIOS name (short name, max 15 chars)
- DOMAINPASS=YourSecureP@ssw0rd!
# Administrator password (CHANGE THIS!)
- DNSFORWARDER=8.8.8.8
# Don't join existing domain - create new one
- HOSTIP=172.20.0.10
# Expose AD-related ports
ports:
# DNS - Required for AD
- "53:53/udp"
- "53:53/tcp"
# LDAP - Directory queries
- "389:389/tcp"
- "389:389/udp"
# LDAPS - Secure LDAP
- "636:636/tcp"
# Kerberos - Authentication
- "88:88/tcp"
- "88:88/udp"
# Global Catalog
- "3268:3268/tcp"
- "3269:3269/tcp"
# Persistent storage for AD database
volumes:
- ./config:/etc/samba/external
- ./data:/var/lib/samba
# Static IP for reliable LDAP connections
networks:
ad-network:
ipv4_address: 172.20.0.10
# Create isolated network for AD
networks:
ad-network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/24
Replace YourSecureP@ssw0rd! with a strong, unique password. This is your AD Administrator password!
# Start the Samba AD container
docker compose up -d
# Wait for domain provisioning (takes 2-3 minutes first time)
echo "Waiting for AD provisioning..."
sleep 60
# Check if container is running
docker ps | grep samba-ad
# Should show: samba-ad ... Up ...
# View logs to confirm domain is ready
docker logs samba-ad 2>&1 | tail -20
# Look for: "Domain provisioned" or similar
# Install LDAP utilities if not present
sudo apt install -y ldap-utils
# Test LDAP connection to Samba AD
# This searches for the domain base
ldapsearch -x -H ldap://localhost:389 \
-D "Administrator@corp.local" \
-w "YourSecureP@ssw0rd!" \
-b "DC=corp,DC=local" \
"(objectClass=domain)"
# You should see output like:
# dn: DC=corp,DC=local
# objectClass: domain
# ...
-x = Simple authentication, -H = LDAP URL, -D = Bind DN (user), -w = Password, -b = Search base
Let's create some test users and groups in Active Directory:
# Enter the Samba container
docker exec -it samba-ad bash
# Inside container: Create Organizational Units
# OU for regular users
samba-tool ou create "OU=Employees,DC=corp,DC=local"
# OU for groups
samba-tool ou create "OU=Security Groups,DC=corp,DC=local"
# OU for IT staff
samba-tool ou create "OU=IT,OU=Employees,DC=corp,DC=local"
# OU for Engineering
samba-tool ou create "OU=Engineering,OU=Employees,DC=corp,DC=local"
# Verify OUs created
samba-tool ou list
# Should show: Employees, Security Groups, IT, Engineering
# Still inside samba-ad container
# Create IT Admin user
samba-tool user create itadmin "ITAdmin@123" \
--given-name="IT" \
--surname="Admin" \
--mail-address="itadmin@corp.local" \
--userou="OU=IT,OU=Employees"
# Create Developer user
samba-tool user create jsmith "DevUser@123" \
--given-name="John" \
--surname="Smith" \
--mail-address="jsmith@corp.local" \
--userou="OU=Engineering,OU=Employees"
# Create another Developer
samba-tool user create mjones "DevUser@123" \
--given-name="Mary" \
--surname="Jones" \
--mail-address="mjones@corp.local" \
--userou="OU=Engineering,OU=Employees"
# Verify users created
samba-tool user list
# Should show: Administrator, itadmin, jsmith, mjones, ...
# Still inside samba-ad container
# Create Cloud Apps Access group
samba-tool group add "Cloud-Apps-Users" \
--groupou="OU=Security Groups" \
--description="Users allowed to access cloud applications"
# Create IT Admins group
samba-tool group add "IT-Admins" \
--groupou="OU=Security Groups" \
--description="IT Administrators with elevated access"
# Create Developers group
samba-tool group add "Developers" \
--groupou="OU=Security Groups" \
--description="Software developers"
# Add users to groups
samba-tool group addmembers "Cloud-Apps-Users" itadmin,jsmith,mjones
samba-tool group addmembers "IT-Admins" itadmin
samba-tool group addmembers "Developers" jsmith,mjones
# Verify group membership
samba-tool group listmembers "Cloud-Apps-Users"
# Should show: itadmin, jsmith, mjones
# Exit the container
exit
Connect Authentik to Active Directory
Authentik will read users and groups from Active Directory automatically
# Get the IP of the Samba AD container
docker inspect samba-ad --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'
# Should show: 172.20.0.10 (from our docker-compose)
# Or get your server's main IP
hostname -I | awk '{print $1}'
# Note this IP - you'll use it in Authentik
Open your Authentik admin panel and configure the LDAP source:
| Field | Value | Explanation |
|---|---|---|
| Name | Corporate AD | Friendly name for this source |
| Slug | corporate-ad | URL-safe identifier |
| Server URI | ldap://YOUR_SERVER_IP:389 | Use your server's IP address |
| Bind CN | Administrator@corp.local | Account to query LDAP |
| Bind Password | (your AD admin password) | Password for bind account |
| Base DN | DC=corp,DC=local | Where to start searching |
If Authentik runs on the same server as Samba AD, you can use ldap://172.20.0.10:389 (the container IP) or your server's LAN IP like ldap://192.168.1.50:389
Still on the LDAP Source configuration page, scroll down to Property Mappings:
| Setting | Value |
|---|---|
| User Property Mappings | Select all LDAP Source - * mappings |
| Group Property Mappings | Select all group mappings |
| User Object Filter | (objectClass=user) |
| Group Object Filter | (objectClass=group) |
| Sync Users | ✅ Enabled |
| Sync Groups | ✅ Enabled |
| Sync Parent Group | Select a parent group (optional) |
Scroll down to the Additional Settings section:
| Setting | Value | Purpose |
|---|---|---|
| Enabled | ✅ Yes | Activate this source |
| Password Login | ✅ Yes | Allow AD password for login |
| Sync Interval | 60 minutes | How often to sync from AD |
Click Create to save the LDAP Source.
You should see itadmin, jsmith, and mjones in the Users list. They'll have a badge indicating they came from the LDAP source.
Enable AD users to access cloud apps
When users login to cloud apps, their password is validated against Active Directory in real-time
Create a custom flow that authenticates against AD:
Add the following stages to your flow:
| Order | Stage Type | Purpose |
|---|---|---|
| 10 | Identification Stage | User enters username |
| 20 | Password Stage (LDAP) | Validate against AD |
| 30 | MFA Validation (optional) | TOTP if configured |
| 40 | User Login Stage | Create session |
This is similar to Azure AD's "Pass-Through Authentication" (PTA) where cloud logins validate against on-prem AD in real-time.
By selecting both LDAP and Inbuilt backends, users can login with either AD credentials or local Authentik accounts. Great for hybrid scenarios!
Connect applications to use AD identities
AD users can now access cloud apps with their corporate credentials via OIDC/SAML
Let's create a test application to verify AD users can login:
| Name | Test Hybrid App |
| Slug | test-hybrid-app |
| Provider | Create new OAuth2 Provider |
| Launch URL | (leave blank for now) |
| Field | Value |
|---|---|
| Name | Test Hybrid OAuth |
| Authorization Flow | hybrid-identity-login |
| Client Type | Confidential |
| Redirect URIs | https://your-app.domain.com/callback |
Restrict application access to specific AD groups:
Add/remove users from AD groups, and their cloud app access automatically updates. Just like Azure AD!
Verify your hybrid identity setup works
Let's verify AD users can login to cloud apps
You'll see the user's full name from AD and their synced groups. The password was validated in real-time against Samba AD!
# List all users in the Employees OU
ldapsearch -x -H ldap://localhost:389 \
-D "Administrator@corp.local" \
-w "YourSecureP@ssw0rd!" \
-b "OU=Employees,DC=corp,DC=local" \
"(objectClass=user)" \
cn mail sAMAccountName
# Expected output:
# dn: CN=IT Admin,OU=IT,OU=Employees,DC=corp,DC=local
# cn: IT Admin
# mail: itadmin@corp.local
# sAMAccountName: itadmin
# ...
# List all groups and their members
ldapsearch -x -H ldap://localhost:389 \
-D "Administrator@corp.local" \
-w "YourSecureP@ssw0rd!" \
-b "OU=Security Groups,DC=corp,DC=local" \
"(objectClass=group)" \
cn member description
# Expected output shows groups with members:
# dn: CN=Cloud-Apps-Users,OU=Security Groups,DC=corp,DC=local
# cn: Cloud-Apps-Users
# member: CN=IT Admin,OU=IT,OU=Employees,DC=corp,DC=local
# member: CN=John Smith,OU=Engineering,OU=Employees,DC=corp,DC=local
# ...
Verify that AD password changes work immediately:
# Enter the Samba container
docker exec -it samba-ad bash
# Change jsmith's password
samba-tool user setpassword jsmith --newpassword="NewP@ssw0rd123"
# Exit container
exit
# Now try logging into Authentik with the NEW password
# The old password should fail immediately!
Because we're using pass-through authentication, password changes in AD take effect immediately for cloud logins. No sync delay!
| Issue | Solution |
|---|---|
| LDAP connection failed | Check container IP, ensure port 389 is accessible |
| No users synced | Verify Base DN matches your domain (DC=corp,DC=local) |
| Login fails with correct password | Check LDAP Backend is selected in Password Stage |
| Groups not showing | Trigger manual sync, check group filter |
Skills gained from this project
You've implemented concepts used in: