A fully automated Active Directory lab environment using Vagrant and Ansible. This lab creates a complete Windows domain environment with a domain controller, member servers (including MS SQL Server), a Windows 10 client, and a Linux server integrated with the Active Directory domain.
- Overview
- Lab Architecture
- Prerequisites
- Quick Start
- Vagrantfile Configuration
- Shared Folder
- Ansible Configuration
- Playbooks
- Roles
- Network Topology
- Usage
- Troubleshooting
This lab environment provisions and configures:
- Domain Controller (win-dc01): Windows Server 2019 running AD DS
- Member Server 1 (win-srv01): Windows Server 2019 with MS SQL Server
- Member Server 2 (win-srv02): Windows Server 2019 with file services
- Windows Client (win-client01): Windows 10 workstation
- Linux Server (linux-srv01): Ubuntu 24.04 with LAMP stack and domain integration
Domain Name: frostylabs.local
Domain NetBIOS: FROSTYLABS
┌─────────────────────────────────────────────────────────────┐
│ frostylabs.local Domain │
│ Network: 192.168.139.0/24 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ win-dc01 │ │ win-srv01 │ │ win-srv02 │ │
│ │ DC + DNS │ │ Member + SQL │ │ Member + IIS │ │
│ │ .139.10 │ │ .139.11 │ │ .139.12 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │win-client01 │ │ linux-srv01 │ │
│ │ Workstation │ │ LAMP + SSSD │ │
│ │ .139.13 │ │ .139.14 │ │
│ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
- Vagrant (2.2.0+)
- VMware Workstation/Fusion or VirtualBox
- This lab uses VMware Desktop provider
- Ansible (2.9+)
- Windows Ansible modules
ansible.windowscollectionmicrosoft.adcollection
- Python (3.8+)
pywinrmfor Windows management
ansible-galaxy collection install ansible.windows
ansible-galaxy collection install microsoft.ad
ansible-galaxy collection install community.windowspip install pywinrm-
Clone this repository or navigate to the lab directory:
cd /path/to/ad-lab -
Update Shared Folder paths in
Vagrantfile:- Edit line 19 and 131 to match your local shared folder path
- Currently set to:
E:/VMWare_Storage/Virtual Machines/Shared-Folder
-
Provision the VMs:
# Start all VMs vagrant up # Or start VMs individually vagrant up win-dc01 vagrant up win-srv01 vagrant up win-srv02 vagrant up win-client01 vagrant up linux-srv01
-
Configure network (if needed):
- Windows VMs: Use PowerShell scripts in
Shared-Folder/ps1/ - Linux VM: Use script in
Shared-Folder/bash/
- Windows VMs: Use PowerShell scripts in
-
Run Ansible playbooks:
# Run all playbooks ansible-playbook labsetup.yml # Or run individual playbooks ansible-playbook playbooks/win-dc01.yml ansible-playbook playbooks/win-srv01.yml ansible-playbook playbooks/win-srv02.yml ansible-playbook playbooks/win-client01.yml ansible-playbook playbooks/linux-srv01.yml
config.vm.provider "vmware_desktop" do |v|
v.gui = true # Show VM GUI
v.memory = 3072 # 3GB RAM per VM
v.cpus = 2 # 2 CPUs per VM
endThe Vagrantfile configures a shared folder between your host and guest VMs:
- Host Path:
E:/VMWare_Storage/Virtual Machines/Shared-Folder - Guest Path (Windows):
C:/Shared-Folder - Guest Path (Linux): Disabled (commented out)
Important: Update the host path on lines 19 and 131 to match your environment.
- Box:
StefanScherer/windows_2019 - IP:
192.168.139.10 - RDP Port:
23389(forwarded from 3389) - WinRM Port:
25985(forwarded from 5985) - Provisioning: Configures WinRM for Ansible using
ConfigureRemotingForAnsible.ps1
- Box:
StefanScherer/windows_2019 - IP:
192.168.139.11 - RDP Port:
33389 - WinRM Port:
35985 - Provisioning: WinRM configuration
- Box:
StefanScherer/windows_2019 - IP:
192.168.139.12 - RDP Port:
43389 - WinRM Port:
45985 - Provisioning: WinRM configuration
- Box:
StefanScherer/windows_10 - IP:
192.168.139.13 - RDP Port:
53389 - WinRM Port:
55985 - Provisioning: WinRM configuration
- Box:
bento/ubuntu-24.04 - IP:
192.168.139.14 - SSH Port:
6222(forwarded from 22) - Shared Folder: Disabled for Linux VM
The Shared-Folder directory contains scripts and utilities accessible from all VMs.
Shared-Folder/
├── README.md
├── ps1/ # PowerShell scripts
│ ├── 1-configure-ip-dc.ps1 # Configure IP for DC
│ ├── 2-configure-ip-srv01.ps1 # Configure IP for srv01
│ ├── 3-configure-ip-srv02.ps1 # Configure IP for srv02
│ ├── 4-configure-ip-client.ps1 # Configure IP for client
│ └── ConfigureRemotingForAnsible.ps1 # Enable Ansible WinRM
└── bash/ # Bash scripts
└── lin-srv01-eth1.sh # Configure IP for Linux
These scripts configure static IP addresses on the VMs' Ethernet1 interface:
- Remove existing IP addresses and routes on Ethernet1
- Set static IP address with /24 subnet
- Configure default gateway (192.168.139.1)
- Set DNS servers
Usage: Run from within the VM or from Shared-Folder:
C:\Shared-Folder\ps1\1-configure-ip-dc.ps1Purpose: Configures WinRM (PowerShell Remoting) for Ansible management.
What it does:
- Enables WinRM service
- Creates self-signed certificate for HTTPS listener
- Configures WinRM to accept connections
- Opens Windows Firewall for WinRM
- Sets appropriate authentication methods
Automatic execution: This script runs automatically during vagrant up as a provisioner.
Security note: Uses self-signed certificates suitable for lab environments only. Production deployments should use CA-signed certificates and Kerberos authentication.
Configures static IP addressing for the Linux server's eth1 interface using Netplan.
Usage:
sudo bash /path/to/lin-srv01-eth1.shLocated at the project root, this file contains Ansible runtime configuration:
[defaults]
inventory = inventory/hosts # Inventory file location
roles_path = roles # Roles directory
host_key_checking = False # Disable SSH key checking
retry_files_enabled = False # Disable retry files
deprecation_warnings = False # Suppress deprecation warnings
[privilege_escalation]
become = False # Don't use sudo by defaultinventory/
├── hosts # Main inventory file
└── group_vars/
├── all.yml # Variables for all hosts
├── win_dc01.yml # DC-specific variables
├── win_srv01.yml # Server 1 variables
├── win_srv02.yml # Server 2 variables
├── win_client01.yml # Client variables
└── linux_srv01.yml # Linux server variables
Defines all lab hosts and groups:
[win_dc01]
dc01 ansible_host="{{ dc_ip }}"
[win_srv01]
srv01 ansible_host="{{ srv01_ip }}"
[win_srv02]
srv02 ansible_host="{{ srv02_ip }}"
[win_client01]
client01 ansible_host="{{ client_ip }}"
[linux_srv01]
linux-srv01 ansible_host="{{ linux_srv01_ip }}"
[windows:children]
win_dc01
win_srv01
win_srv02
win_client01
[windows:vars]
ansible_user={{ vagrant_user }}
ansible_password={{ vagrant_pass }}
ansible_connection=winrm
ansible_winrm_server_cert_validation=ignoreGlobal variables shared across all hosts:
Key variables:
- Domain configuration:
domain,domain_netbios,domain_dn - IP addresses: Static IPs for all hosts
- DNS settings: Forwarders (8.8.8.8, 8.8.4.4)
- Credentials: Administrator, vagrant, and user passwords
- User accounts: admin, bob, alice
- AD Groups: allTeams, DBAOracle, DBASQLServer, etc.
- Windows paths: DNS logs, shares, domain logs
- LAMP configuration: Web domain name, paths, Apache settings
Security note: This file contains plaintext passwords suitable for lab use only. For production, encrypt with ansible-vault encrypt inventory/group_vars/all.yml.
The master playbook that imports all individual playbooks:
---
- import_playbook: playbooks/win-dc01.yml
- import_playbook: playbooks/win-srv01.yml
- import_playbook: playbooks/win-srv02.yml
- import_playbook: playbooks/win-client01.yml
- import_playbook: playbooks/linux-srv01.yml
...Usage:
ansible-playbook labsetup.ymlConfigures the domain controller.
Roles applied:
common: Base Windows configurationdomain_controller: AD DS setup and configuration
Key tasks:
- Install Chocolatey and common packages
- Set hostname and reboot if needed
- Create AD domain
frostylabs.local - Promote to domain controller
- Configure DNS forwarders
- Create domain users (admin, bob, alice)
- Create AD security groups
Configures first member server with SQL Server.
Roles applied:
common: Base Windows configurationmember_server: Domain join and file servicesmssql: Microsoft SQL Server installation
Key tasks:
- Set hostname
- Configure DNS to point to DC
- Join domain
- Install File Server and IIS management
- Create and share network folders
- Install and configure MS SQL Server
Configures second member server.
Roles applied:
common: Base Windows configurationmember_server: Domain join and file services
Key tasks:
- Set hostname
- Configure DNS to point to DC
- Join domain
- Install File Server and IIS management
- Create and share network folders
Configures Windows 10 workstation.
Roles applied:
commonwkstn: Base workstation configuration
Additional tasks:
- Configure DNS to point to DC
- Create and share network folders
- Join domain
- Add user
bobto local Administrators group
Configures Ubuntu Linux server with AD integration.
Roles applied:
linux_server_basic: Base Linux configurationlinux_server_domain: AD/SSSD integrationlamp_server: Apache, MySQL, PHP stack
Key tasks:
- Configure timezone and repositories
- Install essential packages
- Join Linux server to AD domain via SSSD
- Install and configure LAMP stack
- Create web virtual host
Purpose: Base configuration for Windows servers.
Key tasks:
- Install Chocolatey package manager (version 1.4.0)
- Install common packages:
- notepadplusplus
- putty
- python
- git
- 7zip
- wget
- pstools
- sysinternals
- Set hostname
- Configure Administrator account
- Reboot when required
Purpose: Base configuration for Windows workstations.
Key tasks: Similar to common role but tailored for client machines.
Purpose: Configure Active Directory Domain Services.
Dependencies: Requires common role.
Key tasks:
- Create AD domain
frostylabs.local - Promote server to domain controller
- Configure DNS forwarders (8.8.8.8, 8.8.4.4)
- Create domain users:
admin(Domain Admin)bob(Domain User)alice(Domain User)
- Create AD security groups:
- allTeams
- DBAOracle
- DBASQLServer
- DBAMongo
- DBARedis
- DBAEnterprise
- JustATestDemo
Reboots: Multiple reboots during domain creation and DC promotion.
Purpose: Configure member servers and join them to the domain.
Key tasks:
- Set hostname
- Configure DNS client to use domain controller
- Install File Server role
- Install IIS management tools
- Configure ACLs for machine keys
- Create public share (
C:\shares\public) - Join domain
frostylabs.local - Reboot after domain join
Purpose: Install and configure Microsoft SQL Server.
Dependencies: Requires member_server role.
Key tasks:
- Download SQL Server installation media
- Install SQL Server with custom configuration
- Configure SQL Server service
- Set up database authentication
- Configure firewall rules
Purpose: Base configuration for Linux servers.
Key tasks:
- Set timezone (Europe/Rome)
- Enable multiverse repository
- Update package cache
- Install essential packages
- Configure hostname
- Set up networking
Purpose: Integrate Linux server with Active Directory.
Key tasks:
- Install SSSD (System Security Services Daemon)
- Install Kerberos client
- Configure SSSD for AD authentication
- Join server to
frostylabs.localdomain - Enable home directory creation for AD users
- Configure PAM for AD authentication
Purpose: Install and configure Apache, MySQL, PHP stack.
Key tasks:
- Install Apache2 web server
- Install MySQL/MariaDB database
- Install PHP and modules
- Create virtual host for
frostylabs - Configure web root at
/var/www/frostylabs - Set proper permissions for web content
- Enable Apache modules (rewrite, ssl, etc.)
| Hostname | IP Address | Role | OS |
|---|---|---|---|
| win-dc01 | 192.168.139.10 | Domain Controller + DNS | Windows Server 2019 |
| win-srv01 | 192.168.139.11 | Member Server + SQL | Windows Server 2019 |
| win-srv02 | 192.168.139.12 | Member Server + File/IIS | Windows Server 2019 |
| win-client01 | 192.168.139.13 | Workstation | Windows 10 |
| linux-srv01 | 192.168.139.14 | LAMP Server + SSSD | Ubuntu 24.04 |
RDP Access (Remote Desktop):
- win-dc01:
localhost:23389 - win-srv01:
localhost:33389 - win-srv02:
localhost:43389 - win-client01:
localhost:53389
WinRM Access (Ansible):
- win-dc01:
localhost:25985 - win-srv01:
localhost:35985 - win-srv02:
localhost:45985 - win-client01:
localhost:55985
SSH Access:
- linux-srv01:
localhost:6222
- DNS Server: win-dc01 (192.168.139.10)
- Domain Controller: win-dc01 (192.168.139.10)
- SQL Server: win-srv01 (192.168.139.11)
- Web Server: linux-srv01 (192.168.139.14)
# From your host machine
mstsc /v:localhost:23389 # Domain Controller
mstsc /v:localhost:33389 # Server 01
mstsc /v:localhost:43389 # Server 02
mstsc /v:localhost:53389 # Client 01Or use any RDP client:
- Host:
localhost - Port: See port forwarding table above
- Username:
vagrantorAdministrator@frostylabs.local - Password:
vagrantorStrongPass123!
vagrant ssh linux-srv01
# Or via SSH client
ssh -p 6222 vagrant@localhost
# Password: vagrant# Check VM status
vagrant status
# Start specific VM
vagrant up win-dc01
# Restart VM
vagrant reload win-srv01
# Suspend VM
vagrant suspend win-client01
# Resume VM
vagrant resume win-client01
# Stop VM
vagrant halt linux-srv01
# Destroy VM
vagrant destroy win-srv02
# SSH into VM (Linux only)
vagrant ssh linux-srv01
# RDP into Windows VM
vagrant rdp win-dc01# Ping all Windows hosts
ansible windows -m win_ping
# Ping specific host
ansible win_dc01 -m win_ping
# Ping Linux host
ansible linux_srv01 -m ping# Run all playbooks in order
ansible-playbook labsetup.yml
# Run specific playbook
ansible-playbook playbooks/win-dc01.yml
# Run with verbose output
ansible-playbook labsetup.yml -v
# Run with specific inventory
ansible-playbook -i inventory/hosts playbooks/win-srv01.yml# Get hostname from all Windows hosts
ansible windows -m win_shell -a "hostname"
# Check domain membership
ansible win_srv01 -m win_shell -a "systeminfo | findstr Domain"
# Reboot all Windows servers
ansible windows -m win_reboot
# Run command on Linux server
ansible linux_srv01 -m shell -a "hostname"| Username | Password | Role |
|---|---|---|
| Administrator | StrongPass123! | Domain Administrator |
| admin | StrongPass123! | Domain Administrator |
| bob | StrongPass123! | Domain User + Local Admin on client |
| alice | StrongPass123! | Domain User |
| Username | Password | Where |
|---|---|---|
| vagrant | vagrant | All VMs (local admin) |
VMs won't start:
# Check Vagrant status
vagrant status
# Check VMware is running
vagrant plugin list
# Reload VM
vagrant reload <vm-name>Shared folder not mounting:
- Verify the path in Vagrantfile (lines 19, 131) exists on your host
- Ensure VMware Tools is installed in the guest
- Try
vagrant reload <vm-name>to remount
Network issues:
- Verify VMware network adapter is configured
- Check firewall settings on host
- Use the IP configuration scripts in
Shared-Folder/
Cannot connect to Windows hosts:
# Test WinRM connectivity
ansible win_dc01 -m win_ping -vvv
# Verify WinRM is configured
# RDP to the VM and run:
winrm quickconfigAuthentication failures:
- Check credentials in
inventory/group_vars/all.yml - Ensure the ConfigureRemotingForAnsible.ps1 script ran during provisioning
- Verify time sync between Ansible controller and Windows hosts
Module not found:
# Install required collections
ansible-galaxy collection install ansible.windows
ansible-galaxy collection install microsoft.ad
ansible-galaxy collection install community.windowsPython WinRM errors:
# Install/update pywinrm
pip install --upgrade pywinrmDomain join fails:
- Ensure the domain controller (win-dc01) is fully configured first
- Verify DNS is pointing to the DC (192.168.139.10)
- Check domain credentials in group_vars
- Wait a few minutes after DC promotion before joining members
DNS resolution issues:
- Verify DNS server on each VM points to 192.168.139.10
- Use the IP configuration scripts to set DNS
- Check DNS forwarders are configured on DC
Time synchronization:
# On Windows VMs
w32tm /resync
# On Linux VMs
sudo ntpdate -u 192.168.139.10SQL Server not accessible:
- Check SQL Server service is running
- Verify firewall rules allow SQL traffic
- Ensure SQL Server authentication is configured
- Check SQL Server logs in
C:\Program Files\Microsoft SQL Server\
This lab is designed for:
- Active Directory administration practice
- Penetration testing and security research
- Learning Ansible automation for Windows environments
- Testing cross-platform domain integration
- Developing and testing enterprise applications
This lab uses insecure configurations suitable for isolated lab environments only:
- Plaintext passwords in configuration files
- Self-signed certificates
- Disabled certificate validation
- Weak passwords (easily guessable)
- Disabled host key checking
Do not expose this lab to production networks or the internet.
To customize this lab:
- Change domain name: Edit
domainininventory/group_vars/all.yml - Add more users: Add entries to playbooks or roles
- Modify IP addresses: Update Vagrantfile and group_vars
- Add more VMs: Add new VM definitions to Vagrantfile
- Install additional software: Extend roles or create new ones
- Memory: Ensure your host has enough RAM (recommended: 16GB+)
- CPU: More cores = better performance
- Storage: SSDs significantly improve VM performance
- Snapshots: Take snapshots after successful provisioning for quick recovery
# Stop all VMs
vagrant halt
# Destroy all VMs (cannot be undone!)
vagrant destroy -f
# Remove Vagrant boxes (optional)
vagrant box remove StefanScherer/windows_2019
vagrant box remove StefanScherer/windows_10
vagrant box remove bento/ubuntu-24.04This project is provided as-is for educational and testing purposes.
Feel free to submit issues or pull requests for improvements.
Happy Labbing!