//AwesomeOps Part 5: Ansible CIS Windows Images

Platform Engineering

AwesomeOps Part 5: Ansible CIS Windows Images

M Mentat CollectiveJun 26, 20238 min readShare

Published

Jun 26, 2023

Read time

8 min read

Focus

Windows Server CIS hardening with Packer, Ansible, and repeatable image pipelines

More AwesomeOps? Yes please. This article focuses on one of the most overlooked topics in enterprise engineering: hardened Windows images.

Hardening Windows images may not feel as flashy as AI or large language models, but Mentat’s view is that infrastructure should be built like a house: worry about the foundation before you pick the couch in the living room.

The post’s argument is straightforward: if your company has compliance obligations, hardened Windows Server CIS base images are not optional. They are one of the most effective places to begin securing the business.

Windows CIS Context

The Center for Internet Security, or CIS, is a global security-focused nonprofit dedicated to identifying and mitigating cyber risk. CIS-hardened Windows Server images align with a long list of enterprise and public-sector standards including DoD SRG, PCI DSS, HIPAA, FISMA, FedRAMP, NIST, and DISA STIG.

That list matters because it highlights the real use case: if an organization must conform to industry security standards and compliance requirements, then it needs a repeatable way to bake compliant Windows Server base images.

Mentat frames this with a long historical analogy. Strong defenses have always mattered, whether they were Roman walls, medieval castles, or modern digital platforms. Attackers adapt, defenders reinforce, and the strongest advantages tend to come from hardening the base before the attack arrives.

The same logic applies in modern infrastructure. Security incidents are expensive, and hardened operating-system images are one of the clearest ways to reduce risk before workloads ever go live.

The article also makes a practical business case: security should not be treated as the opposite of revenue generation. It is a necessary precondition for continuing to generate revenue safely.

Why Start at the Base Image?

Mentat’s recommendation is to secure the organization in small incremental steps, beginning at the operating-system layer that supports every downstream application.

That is why hardened images matter so much. If the base image is clean, repeatable, and aligned to CIS controls, every future deployment starts from a better place. If the base image is weak, every new machine begins life with the same inherited problems.

Hardened images create a consistent foundation across environments.
They reduce the number of one-off fixes teams have to perform after build time.
They support compliance efforts by making security controls part of the image pipeline instead of an afterthought.
They make later drift-control pipelines much easier because hosts begin from a much closer desired state.

The Tech: Packer + Ansible

The practical implementation starts with Packer and Ansible.

Mentat’s advice is to build identical Windows Server 2022 images across compute platforms and to reuse the same Ansible playbooks both during image creation and later in drift-control pipelines against living infrastructure.

That pattern keeps the automation model simpler over the long term. The image build and the ongoing drift-control process reinforce each other instead of drifting into separate stacks.

The first step is to create or extend a Packer build block for a hardened Windows Server 2022 image. The sample shown in the original post runs Windows Update, then an Ansible CIS hardening playbook, then restores WinRM configuration and reboots the machine.

Packer build skeleton with Windows Update and Ansible CIS provisioning
build {
  sources = [
    "source.vsphere-iso.windows-server-2022-cis-dap"
  ]

  provisioner "windows-update" {
    pause_before = "30s"
    search_criteria = "IsInstalled=0"
    filters = [
      "exclude:$_.Title -like '*VMware*'",
      "exclude:$_.Title -like '*Preview*'",
      "exclude:$_.Title -like '*Defender*'",
      "include:$true",
      "update_limit: 25"
    ]
    update_limit = 25
  }

  provisioner "ansible" {
    command = "../../../scripts/windows/win-cis-ansible-wrapper.sh"
    playbook_file = "${var.ansible_cis_dir}/site.yml"
    user = var.build_username
    use_proxy = false
    extra_arguments = [
      "--extra-vars",
      "become_method=runas
ansible_windows_domain_role='Stand-alone server' ansible_winrm_server_cert_validation=ignore ansible_password=${var.build_password} win19cis_admin_username=${var.build_username} win19cis_guest_username=scrambledguest newadministratorname=${var.ansible_username} newguestname=scrambledguest
run_audit=true
long_running=true
is_implemented=false
win2016cis_is_standalone=true
audit_time=post
audit_capture_path=${var.ansible_cis_dir}
section01_patch=true
section02_patch=true
section09_patch=true
section17_patch=true
section18_patch=true
rule_1_2_1=false
rule_2_3_1_1=false
rule_9_1_1=false
rule_9_2_1=false
# This control will have to be set to Enabled (1) to allow for continued remote management via Ansible following machine restart
rule_18_9_102_2_2=false
# This control will have to be set to Enabled (1) to allow for continued remote management via Ansible following machine restart
rule_18_9_103_1=false
min_ansible_version=2.9"
    ]
  }

  provisioner "powershell" {
    script = "../../../scripts/windows/winrm-setup.ps1"
  }

  provisioner "windows-restart" {
    restart_check_command = "powershell -command "& {Write-Output 'restarted.'}""
  }
}

Why the Packer Pattern Matters

The original article breaks the flow into a few core pieces.

Run Windows Update during image creation so new images begin with current patches.
Use the Ansible provisioner to execute the CIS hardening playbook against the temporary build host.
Pass environment-specific values through `extra_arguments` so the same playbook can be shaped to fit enterprise requirements.
Restore WinRM access and perform controlled restarts so remote automation continues to work after hardening changes.

Understanding the CIS Playbook Inputs

The article emphasizes that the long Ansible variable block is not as intimidating as it first appears. Most of it is simply enabling or disabling specific sections and rules in a structured way.

Mentat specifically calls out the work of the MindPoint Group and the Windows 2022 CIS playbook from the ansible-lockdown project as a strong foundation for this approach.

The technique is to enable entire sections globally and then selectively disable or override individual rules where operational reality demands it.

Section-level enablement and rule-level exceptions
section01_patch=true
section02_patch=true
section09_patch=true
section17_patch=true
section18_patch=true

rule_1_2_1=false
rule_2_3_1_1=false
rule_9_1_1=false
rule_9_2_1=false
# This control will have to be set to Enabled (1) to allow for continued remote management via Ansible following machine restart
rule_18_9_102_2_2=false
# This control will have to be set to Enabled (1) to allow for continued remote management via Ansible following machine restart
rule_18_9_103_1=false

Review the Code, Especially the Exceptions

One of the most useful parts of the original post is its warning to always review the hardening code closely. Some security controls have side effects that can break the very automation path you depend on.

The example highlighted in the post is a WinRM-related rule. Mentat had to disable a specific CIS rule so Ansible could continue connecting to hosts after machine restarts.

Example WinRM-related CIS task
- name: "18.9.102.2.2 | PATCH | Ensure Allow remote server management through WinRM is set to Disabled"
  ansible.windows.win_regedit:
    path: HKLM:\Software\Policies\Microsoft\Windows\Winrm\Service
    name: AllowAutoConfig
    data: 1
    type: dword
  when:
    - rule_18_9_102_2_2
    - not win_skip_for_test
  tags:
    - level2-domaincontroller
    - level2-memberserver
    - rule_18.9.102.2.2
    - automated

Finding

Security automation is rarely just “turn everything on.” Practical hardening means understanding which controls are safe to enforce universally and which need exceptions to preserve remote management and platform operability.

Why win_regedit Shows Up Everywhere

The article also circles back to a recurring pattern across the AwesomeOps series: the ansible.windows.win_regedit module does a tremendous amount of work for Windows automation teams.

Instead of burying intent inside long PowerShell scripts, teams can declare the registry path, value name, data, and type directly in self-documenting Ansible tasks.

That is part of why the playbook is so approachable: the tasks read clearly, and teams can reason about them without untangling a giant script.

Mentat’s broader point is that high-leverage Windows automation comes from combining simple, declarative modules with careful review and disciplined exceptions.

From Hardened Images to Ongoing Compliance

Once the Packer build completes, the organization has a hardened Windows Server 2022 image that can be deployed across supported compute platforms. But the article makes clear that image creation alone is not enough.

If a team really wants to maintain compliance, it should take the same CIS playbook and run it daily against the golden inventory in a scheduled pipeline. That extends image hardening into ongoing operational compliance.

The final piece is telemetry: send Ansible and AAP output into Elasticsearch so compliance dashboards can expose where hosts are drifting and where remediation keeps succeeding or failing.

Next Time on AwesomeOps

The post closes by connecting directly to the next article in the sequence. After the community poll, Ansible CIS images came out on top and the runner-up topic was a deeper look at Windows drift control.

That next step became AwesomeOps Part 6: Windows Server 2022 Ansible Drift Control In-Depth, where the image-hardening foundation gets extended into layered drift-control operations.

It is a nice handoff in the series: harden the base first, then control what changes afterward.

References

CIS Hardened Images: https://www.cisecurity.org/cis-hardened-images

MindPoint / ansible-lockdown Windows 2022 CIS project: https://github.com/ansible-lockdown/Windows-2022-CIS

Packer Windows Update plugin: https://github.com/rgl/packer-plugin-windows-update

Packer Ansible provisioner docs: https://developer.hashicorp.com/packer/plugins/provisioners/ansible/ansible

Ansible win_regedit docs: https://docs.ansible.com/ansible/latest/collections/ansible/windows/win_regedit_module.html

AwesomeOps Part 5: Ansible CIS Windows Images

Key takeaway

Ready to automate smarter?

The strongest Windows security posture starts at the base image: create a repeatable hardened golden image, understand which CIS controls need exceptions, and reuse that same automation for ongoing compliance.