Hello again, this post will explain how to create a Windows Server virtual machine with Vagrant, WSL and Ansible. I assume that you already saw my previous Windows Server post where I explain how to create a Windows Server vm, so go check that out if you didn't :)
Before we start, Plugins!
Installation
Windows
So, to put in action some plugins into our Vagrantfile we need to installed them directly to our terminal.
To do so, open an Powershell and install the following plugins (note that this plugin is for Windows OS):
vagrant plugin install vagrant-reload
This will allow us to reload our vm during the creation of the vm.
Others OS
Now, we want to use windows features but are using a Linux or MacOS.
For that, we need to install the following plugins in our Linux or MacOS machine:
vagrant plugin install vagrant-reload
vagrant plugin install winrm
vagrant plugin install winrm-fs
vagrant plugin install winrm-elevated
This will allow us to reload our vm and to use windows features with vagrant;
Now that we've have our plugins installed lets continue;
WSL
What's WSL and what it does? WSL stands for Windows Subsystem for Linux and, by installing it on our Windows Server, it will allow us, basically, to have Linux on a Windows terminal.
Meaning that you can, for example, install a tool in your Windows vm using Linux commands like wsl sudo apt ansible -y (this command will install Ansible in your Windows virtual machine).
But to use WSL we need to install it! And to install it we're going to use Vagrant. Lets take a look at our Vagrantfile:
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "mcree/win2019"
config.vm.box_version = "1.0.1584095692"
config.vm.provider "virtualbox" do |v|
v.name = "Windows Server 2019"
v.memory = "2048"
end
config.vm.provision "shell", inline: <<-SHELL
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
SHELL
end
If this vagrantfile looks familiar it should! This is the vagrantfile from our previous post where we define our machine configuration and installed Chocolatey.
Now what we want to do is install WSL and to do so we need to add the installation command into our Shell provisioner.
So, copy paste this to the shell terminal in your vagranfile:
Enable-WindowsOptionalFeature -FeatureName Microsoft-Windows-Subsystem-Linux -Online -NoRestart -WarningAction SilentlyContinue
So, our vagrantfile should look like this for now:
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "mcree/win2019"
config.vm.box_version = "1.0.1584095692"
config.vm.provider "virtualbox" do |v|
v.name = "Windows Server 2019"
v.memory = "2048"
end
config.vm.provision "shell", inline: <<-SHELL
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
Enable-WindowsOptionalFeature -FeatureName Microsoft-Windows-Subsystem-Linux -Online -NoRestart -WarningAction SilentlyContinue
SHELL
end
So, we now have WSL installed in our Windows Server vm! This is great and we now have the freedom to use it at will!
Since we installed Chocoaltey and WSL we want to be sure that the machine takes in to account the modifications applied.
For that we will use a provisioner (shell) reload:
config.vm.provision :reload
We will add this after our shell provisioner just like this:
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "mcree/win2019"
config.vm.box_version = "1.0.1584095692"
config.vm.provider "virtualbox" do |v|
v.name = "Windows Server 2019"
v.memory = "2048"
end
config.vm.provision "shell", inline: <<-SHELL
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
Enable-WindowsOptionalFeature -FeatureName Microsoft-Windows-Subsystem-Linux -Online -NoRestart -WarningAction SilentlyContinue
SHELL
# trigger reload
config.vm.provision :reload
end
Now that our provisioner is reloaded we can install Kali Linux (Linux distribution base on Debian).
For that we're going to open another termninal and use chocolatey to install it.
Right after installing kali linux we're going to reload our provisioner once again.
This will give us certitude that everything was restarted including the virtual machine itself!
So, lets see what we need to add:
# execute code after reload
config.vm.provision "shell", inline: <<-SHELL
choco install wsl-kalilinux -y
SHELL
# trigger reload
config.vm.provision :reload
And now that everything is fresh and clean lets open another shell terminal and start using WSL!
To start using WSL and see if it works lets add a shell with a simple package update:
wsl sudo apt update
Pretty easy right? So, lets see how we can use it effectively.
To try it out lets install some tools that we're going to need.
So lets install Ansible and unzip package:
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "mcree/win2019"
config.vm.box_version = "1.0.1584095692"
config.vm.provider "virtualbox" do |v|
v.name = "Windows Server 2019"
v.memory = "2048"
end
config.vm.provision "shell", inline: <<-SHELL
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
Enable-WindowsOptionalFeature -FeatureName Microsoft-Windows-Subsystem-Linux -Online -NoRestart -WarningAction SilentlyContinue
SHELL
# trigger reload
config.vm.provision :reload
# execute code after reload
config.vm.provision "shell", inline: <<-SHELL
wsl sudo apt update
wsl sudo apt install -y ansible
wsl sudo apt install -y unzip
SHELL
end
Why do we need to install Ansible and Unzip might you ask? Well, we'll need to unzip some files so that's why we need Unzip.
For Ansible it requires a little bit more explaination, come with me :)
Ansible
Ansible is an automation engine, that works with .yml files called playbooks, that automates cloud provisioning, configuration management, application deployment, intra-service orchestration, and many other IT needs.
It uses no agents and no additional custom security infrastructure, so it's easy to deploy - and most importantly, it uses a very simple language (YAML, in the form of Ansible Playbooks) that allow you to describe your automation jobs in a way that approaches plain English.
We also have a hosts (also known as Inventory) file. That's where we're going to add our target machines that we wish to run the playbooks.
Go check the link for a more deep and detailed information about Ansible and what it does
So, to use Ansible we need a working playbook, hosts and a bunch of other stuff! And for that we're going to use wget to donwload a zip file containing all of this (our unzip package will come in handy :D )
Just copy paste this to your provisioner:
wsl wget https://github.com/j0rdan-m/vagrant_wsl_ansible/archive/master.zip
This will download the zip file.
But we need to unzip it, so:
wsl unzip master.zip
Thanks to this work we now have working playbooks available to us.
But before we check them out lets configure our hosts file. We will just add the localhost machine into the hosts file with an user, password, connection method and port configuration.
If everything is correct this should work perfectly with your playbooks
wsl sudo bash -c "echo [self] >> /etc/ansible/hosts"
wsl sudo bash -c "echo 127.0.0.1 >> /etc/ansible/hosts"
wsl sudo bash -c "echo [self:vars] >> /etc/ansible/hosts"
wsl sudo bash -c "echo ansible_port=5985 >> /etc/ansible/hosts"
wsl sudo bash -c "echo ansible_connection=winrm >> /etc/ansible/hosts"
wsl sudo bash -c "echo ansible_winrm_transport=basic >> /etc/ansible/hosts"
wsl sudo bash -c "echo ansible_user=vagrant >> /etc/ansible/hosts"
wsl sudo bash -c "echo ansible_password=vagrant >> /etc/ansible/hosts"
And, just to be sure that everything is correct, lets ping our vm:
wsl ansible self -m win_ping
Now that the hosts file is correct we can advance to our playbooks!
We have 3 to be exact! One to install IIS, one to install some tools (Git, VSCode and SumatraPDF) and the last one that creates a service user and gives him the rights to the correct folders.
To use them we need to use ansible-playbook command just like this:
wsl ansible-playbook vagrant_wsl_ansible-master/tools.yml
wsl ansible-playbook vagrant_wsl_ansible-master/iis.yml
wsl ansible-playbook vagrant_wsl_ansible-master/users.yml
This will launch each playbook in the order presented.
So, our playbook should look something like this:
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "mcree/win2019"
config.vm.box_version = "1.0.1584095692"
config.vm.provider "virtualbox" do |v|
v.name = "Windows Server 2019"
v.memory = "2048"
end
config.vm.provision "shell", inline: <<-SHELL
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
Enable-WindowsOptionalFeature -FeatureName Microsoft-Windows-Subsystem-Linux -Online -NoRestart -WarningAction SilentlyContinue
SHELL
# trigger reload
config.vm.provision :reload
# execute code after reload
config.vm.provision "shell", inline: <<-SHELL
choco install wsl-kalilinux -y
SHELL
# trigger reload
config.vm.provision :reload
# execute code after reload
config.vm.provision "shell", inline: <<-SHELL
wsl sudo apt update
wsl sudo apt install -y ansible
wsl sudo apt install -y unzip
wsl wget https://github.com/j0rdan-m/vagrant_wsl_ansible/archive/master.zip
wsl unzip master.zip
wsl sudo bash -c "echo [self] >> /etc/ansible/hosts"
wsl sudo bash -c "echo 127.0.0.1 >> /etc/ansible/hosts"
wsl sudo bash -c "echo [self:vars] >> /etc/ansible/hosts"
wsl sudo bash -c "echo ansible_port=5985 >> /etc/ansible/hosts"
wsl sudo bash -c "echo ansible_connection=winrm >> /etc/ansible/hosts"
wsl sudo bash -c "echo ansible_winrm_transport=basic >> /etc/ansible/hosts"
wsl sudo bash -c "echo ansible_user=vagrant >> /etc/ansible/hosts"
wsl sudo bash -c "echo ansible_password=vagrant >> /etc/ansible/hosts"
wsl ansible self -m win_ping
wsl ansible-playbook vagrant_wsl_ansible-master/tools.yml
wsl ansible-playbook vagrant_wsl_ansible-master/iis.yml
wsl ansible-playbook vagrant_wsl_ansible-master/users.yml
SHELL
end
We now have a fully working Windows Server virtual machine with Ansible and a bunch of other cool stuff in it!
Hope that this was helpfull and make sure to check the other posts ;)