Hardening a single server manually takes hours and is error-prone. PowerShell Desired State Configuration (DSC), Ansible playbooks, and Bash scripts turn hardening into code: repeatable, testable, and version-controlled. This lesson will teach you to write idempotent hardening scripts that enforce CIS settings, configure services, and audit compliance—so every new server is born secure.
DSC defines a desired state for Windows features, registry settings, and services. For example, the 'Registry' resource ensures a key has a specific value; 'Service' ensures a service is stopped and disabled. DSC can be pushed or pulled via a configuration server. Combine DSC with the 'SecurityPolicyDsc' module to manage User Rights Assignment and Audit Policy. The configuration becomes a MOF file applied to nodes.
# DSC configuration to disable Print Spooler and set UAC registry
Configuration HardeningBaseline {
Import-DscResource -ModuleName PSDesiredStateConfiguration
Node localhost {
Service Spooler {
Name = "Spooler"
State = "Stopped"
StartType = "Disabled"
}
Registry UACEnableLUA {
Key = "HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System"
ValueName = "EnableLUA"
ValueData = "1"
ValueType = "Dword"
}
}
}
HardeningBaseline -OutputPath C:\DSC\mof
Start-DscConfiguration -Path C:\DSC\mof -Wait -VerboseThe above DSC configuration ensures Print Spooler is disabled and UAC is enabled. Running it idempotently means it can be reapplied without errors.
Ansible uses YAML playbooks and modules to manage Linux, Windows, and macOS. The 'ansible-hardening' role (OpenStack) and 'CIS Ubuntu' role implement many CIS recommendations. You write tasks that check if a configuration is already set, and only modify if needed. Ansible's idempotency makes it ideal for continuous hardening. Store playbooks in Git and run them in CI/CD pipelines against golden images.
# Ansible task to disable root SSH login
- name: Ensure PermitRootLogin is no
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PermitRootLogin'
line: 'PermitRootLogin no'
validate: 'sshd -t -f %s'
notify: restart sshd💡 The 'validate' parameter checks sshd syntax before applying the change, preventing lockouts. Always use validations when editing critical configs.
| Tool | Platform | Idempotency | Best For |
|---|---|---|---|
| PowerShell DSC | Windows | Yes | Domain-joined Windows servers |
| Ansible | Linux/Windows/macOS | Yes | Heterogeneous environments, cloud |
| Bash scripts | Linux/macOS | Manual (need if-checks) | Quick one-off hardening, embedded in AMI builds |
For cloud-init or simple VMs, a Bash script with conditional checks works. Use 'grep -q' to check if a setting already exists, or 'sysctl -w' to set kernel parameters. Always write scripts that are safe to run multiple times. Example: check if a line exists in /etc/sysctl.conf before appending. Combine with 'set -e' to fail early.
⚠️ Idempotent doesn't mean safe. A hardening script can still break an application even if it runs successfully. Always test on a clone of production first.
Verify exercises to earn ★ 180 XP and unlock next lab level.