One way to ensure that your VMware ESXi hosts have a consistent and repeatable configuration; is with the use of Ansible. I have created an ansible playbook that can be run against a VMware ESXi host to a desired configuration and run on a weekly basis to check for configuration drift. The true power is running the ansible playbook against multiple hosts and be assured the configuration are the same on all hosts in minutes.
During this series of blog posts, I am showcasing the process of updating my outdated Ansible playbooks. By doing so, this allows me to take advantage of newer versions of Ansible along with updated vendor modules.
As I have mentioned in several of my previous blog posts, I am a huge fan of automation and use it whenever possible and I hope this motivates you as well.

Ansible Stand Outs
No Agents
Ansible is Agentless, you only need to install Ansible from where you want to run in from. (Linux based)
YAML
Ansible is YAML based, its coding / scripting as close to understandable / readable tasks.
Procedural
Ansible is Procedural, Playbooks run tasks / procedures in order (order of operations)
Ecosystem
Ansible has a large Ecosystem, not only VMware but other Vendors like Cisco and NetApp
Terminology use by Ansible
Modules
Modules are what does the magic, they are all written in Python by VMware and other vendors, and you as a user should never had to open or modify. As an end-user, you only need to know what Module to call in your Playbook.
Playbooks
Playbook is the configuration file that Ansible will reference it defines what you want to do and the order you want to run the task in.
Roles
Roles are a collection of tasks, variables and templates from playbooks.
VMware ESXI Host Configuration
Now that we have VM running Redhat RHEL9 with Ansible, along with the VMware ‘pymomi’ module installed, we can start creating a playbook to configure an ESXi host.
This playbook will consist of most commonly used configurations along with some advanced VMware security hardening settings that I wrote about in another blog post
Create Ansible Playbook
Ther are various editors when it comes to building your playbooks, I decide to use Microsoft Visual Studio Code. This allows me to ssh directly to my RHEL9 VM and create / validate my playbooks.

VARS FILE
In my playbooks I make use of a variables, this way if I need to make DNS or NTP changes for example, I only need to make those changes on my vars.yml file.

Here is a sample of what I use, feel free to make adjustments that fit your environment
# Add ESXi Hosts that you want to modify with the same information
esxi_info:
- { name: '10.11.16.180', vmo: "10.11.17.180", nfs_ip: "10.11.14.180", netmask: "255.255.255.0" }
# - { name: '10.10.20.221', vmo: "10.10.40.221", nfs_ip: "10.10.100.221", netmask: "255.255.255.0" }
#DNS and NTP
upstream_dns1: "10.11.20.11"
upstream_dns2: "10.11.20.12"
upstream_ntp1: "0.pool.ntp.org"
upstream_ntp2: "1.pool.ntp.org"
#Windows Server and Domain Controller Information
dc_hostname: DC1--CORE1
dc_address: "10.10.10.10"
domain_name: "humbledgeeks.com"
ad_user: "admin.allen"
ad_password: "P@ssw0rd"
esx_admins_group: "ESXi_Admins"
#VMware ESXi Host Infrastructure
esxi_address: "10.11.16.180"
esxi_password: "P@sw0rd"
esxi_netmask: "255.255.255.0"
esxi_netmask_cidr: "24"
esxi_gateway: "10.11.16.1"
esxi_hostname: "wcv-hst-esxi01"
esxi_username: "root"
esxi_local_datastore: "HPE_Local"
ext_storage_ds_name: 'NFS_DS01'
ext_storage_ds_type: 'nfs'
ext_storage_nfs_server: '10.11.14.10'
ext_storage_nfs_path: 'NFS_DS01'
validate_certs: "no"
service_policy: 'pressent'
tsm_policy: 'on'
tsm_state: 'present'
ESXI PLAYBOOK
The Red Hat Ansible website has various modules, along with examples on how to configure and manage your VMware environment using Ansible playbooks. You just need to find what you are trying to accomplish, copy / modify the sample and make it your own.
Now lets start building a ESXi Conifg playbook with most commonly used settings
ESXi MANAGE SERVICES
Here in my playbook, I am calling on the vars.yml file I created in the previous step.

I am creating a playbook called ‘ESXiConfig.yml’ where I will build out the tasks that I typically configure on an ESXi host.
When configuring a VMware ESXi host, I oftentimes require SSH to be enabled but best security practices state you should disable when not required. So, I usually add this to my playbook, this was I can easily enable or disable as need and can easily use it to validate that SSH is disabled across my environment.
The “community.vmware.vmware_host_service_manager” module can be used to manage (start or stop) services on VMware ESXi hosts.
To run / validate your playbook from the terminal run the following command.
As I build out my playbook, I like to periodically test and validate, this help troubleshoot along the way.
From your RHEL9 VM, change to the directory where your playbook resides and run the following command
ansible-playbook ESXi_Config.yml
As the tasks in the playbook run, you will see a ‘green’ text for items that don’t need any modifications.

---
- hosts: localhost
name: ESXi Basic Configuration
gather_facts: false
vars:
esxi_login: &esxi_login
hostname: '{{ item.name }}'
username: '{{ esxi_username }}'
password: '{{ esxi_password }}'
validate_certs: no
tsm_policy: on
tsm_state: present
vars_files:
vars.yml
tasks:
# Enable / Disable SSH on Host
- name: Enable SSH (TSM-SSH) for an ESXi Host with Service policy
community.vmware.vmware_host_service_manager:
<<: *esxi_login
esxi_hostname: '{{ esxi_address }}'
service_name: TSM-SSH
service_policy: on
state: present # Chnage to Absent if you want to disable SSH
delegate_to: localhost
loop: '{{ esxi_info }}'
- name: Enable ESX Shell (TSM) setting for an ESXi Host with Service policy
community.vmware.vmware_host_service_manager:
<<: *esxi_login
esxi_hostname: '{{ item.name }}'
service_name: TSM
service_policy: on
state: present # Chnage to Absent if you want to disable SSH
delegate_to: localhost
loop: '{{ esxi_info }}'
ESXi Security Configuration Tasks
The vSphere Security Configuration Guide (SCG) 7 is the baseline for security hardening of VMware vSphere itself, and the core of VMware security best practices. The VMware vSphere Security Hardening Guide gives recommended guidance for vSphere Administrators looking to protect their infrastructure.
The “community.vmware.vmware_host_config_manager” module can be used to configure advanced settings on VMware ESXi hosts.
I have chosen most of the ESXi configuration options from the vSphere Security Configuration Guide (SCG) 7 along with other best practices to enforce VMware ESXi security configurations across my environment.
As I mentioned earlier, I like running and validating my playbooks as I add new taks, lets do that now.
ansible-playbook ESXiConfig.yml
As you can see, the ‘Advanced Options’ have been applied without errors and we can continue building on the playbook.
ESXi Storage Advanced Settings (NFS)
Here are some additional settings for those using NetApp NFS that can be added to your playbook.
- name: Set Advance ESXi and NetApp VSC Values. # Apply VMware / NetApp NFS Best Practices
community.vmware.vmware_host_config_manager:
<<: *esxi_login
esxi_hostname: '{{ item.name }}'
options:
"Net.TcpipHeapSize": 32
"Net.TcpipHeapMax": 1536
"NFS.MaxVolumes": 256
"NFS41.MaxVolumes": 256
"NFS.MaxQueueDepth": 128
"NFS.HeartbeatMaxFailures": 10
"NFS.HeartbeatFrequency": 12
"NFS.HeartbeatTimeout": 5
"Disk.QFullSampleSize": 32
"Disk.QFullThreshold": 8
delegate_to: localhost
loop: '{{ esxi_info }}'
ESXi DNS / NTP Configuration Tasks
The “community.vmware.vmware_host_dns” module can be used to configure DNS settings on VMware ESXi hosts.

The “community.vmware.vmware_host_ntp” module can be used to configure NTP settings on VMware ESXi hosts.

---
- hosts: localhost
name: ESXi Basic Configuration
gather_facts: false
vars:
esxi_login: &esxi_login
hostname: '{{ item.name }}'
username: '{{ esxi_username }}'
password: '{{ esxi_password }}'
validate_certs: no
tsm_policy: on
tsm_state: present
vars_files:
vars.yml
tasks:
- name: Enable SSH (TSM-SSH) for an ESXi Host with Service policy # Enable SSH on ESXi Host
community.vmware.vmware_host_service_manager:
<<: *esxi_login
esxi_hostname: '{{ esxi_address }}'
service_name: TSM-SSH
service_policy: on
state: present # Chnage to Absent if you want to disable SSH
delegate_to: localhost
loop: '{{ esxi_info }}'
- name: Enable ESX Shell (TSM) setting for an ESXi Host with Service policy # Enable SSH Service
community.vmware.vmware_host_service_manager:
<<: *esxi_login
esxi_hostname: '{{ item.name }}'
service_name: TSM
service_policy: on
state: present # Chnage to Absent if you want to disable SSH
delegate_to: localhost
loop: '{{ esxi_info }}'
# Set Advanced Options
- name: Set Advanced Options
community.vmware.vmware_host_config_manager:
<<: *esxi_login
esxi_hostname: '{{ item.name }}'
options:
"Config.HostAgent.log.level" : info
"UserVars.ESXiShellInteractiveTimeOut": 900
"UserVars.ESXiShellTimeOut": 900
"UserVars.DcuiTimeOut": 600
"Security.AccountLockFailures": 5
"Security.AccountUnlockTime": 900
"Security.PasswordHistory" : 5
"Security.PasswordQualityControl": "similar=deny retry=3 min=disabled,disabled,disabled,disabled,15"
"UserVars.SuppressShellWarning": 1
"UserVars.ESXiVPsDisabledProtocols" : "sslv3,tlsv1,tlsv1.1"
"VMkernel.Boot.execInstalledOnly" : true
"Mem.ShareForceSalting": 2
"Misc.BlueScreenTimeout": 60
"Config.HostAgent.plugins.solo.enableMob": false
#"VMkernel.Boot.allowCoreDumpOnUsb": 'TRUE'
#"Annotations.WelcomeMessage": 'This system is intended for the use of authorized users only'
#'Syslog.global.logDir': '[NFS_DS01]scratch/{{ item.name }}'
delegate_to: localhost
loop: '{{ esxi_info }}'
- name: Set Advance ESXi and NetApp VSC Values. # Apply VMware / NetApp NFS Best Practices
community.vmware.vmware_host_config_manager:
<<: *esxi_login
esxi_hostname: '{{ item.name }}'
options:
"Net.TcpipHeapSize": 32
"Net.TcpipHeapMax": 1536
"NFS.MaxVolumes": 256
"NFS41.MaxVolumes": 256
"NFS.MaxQueueDepth": 128
"NFS.HeartbeatMaxFailures": 10
"NFS.HeartbeatFrequency": 12
"NFS.HeartbeatTimeout": 5
"Disk.QFullSampleSize": 32
"Disk.QFullThreshold": 8
delegate_to: localhost
loop: '{{ esxi_info }}'
- name: Configure ESXi hostname and upstream DNS servers # Configure Host DNS Settings
community.vmware.vmware_host_dns:
<<: *esxi_login
domain: '{{ domain_name }}'
type: static
dns_servers:
- '{{ upstream_dns1 }}'
- '{{ upstream_dns2 }}'
loop: '{{ esxi_info }}'
- name: Set NTP servers for an ESXi Host # Configure Host NTP Settings
community.vmware.vmware_host_ntp:
<<: *esxi_login
esxi_hostname: '{{ item.name }}'
state: present
ntp_servers:
- '{{ upstream_ntp1 }}'
- '{{ upstream_ntp2 }}'
delegate_to: localhost
loop: '{{ esxi_info }}'
- name: Start ntpd service setting for all ESXi Host in given Cluster # Enable NTP Service
Now that you see how easy it is to put together an ESXi Configuration playbook, this can now be run on a schedule to catch any configuration drift.
For this exercise, I am going to make a NTP change, and see what happens when I run the ESXi_Config.yml playbook.














Thanks for sharing
I love the write up, I did notice where it says “service_policy”, I do see an error:
-> service_policy: pressent
I think it should say “present”, but I could be missing something (I see it in the image and the text).
Please be advised.
Todd