As promised, this is the follow up to my post about using Ansible to provision the hacklab from @myexploit2600's guide. Once again, we're going to be standing on the shoulders of giants and this time it's Jordan Borean (@BoreanJordan), one of the Ansible developers, and Gusztáv Varga (@gusztavvargadr), a principal software engineer at Knab bank. If you haven't read the previous post, give it a ganders.
For our lab, we need Windows Server 2016 and either Windows 7 or 10 (I've opted for 10). Jordan Borean who is specifically involved in the development of the Windows support in Ansible has produced a Server 2016 Vagrant box while Guztáv has produced a Windows 10 Enterprise box. Both boxes attach evaluation licenses on deployment (180 days and 90 days respectively) which ties very neatly into our desire to be able to nuke and reboot the hacklab at will. Both boxes use the credentials vagrant:vagrant and expose WinRM listeners, allowing us to immediately communicate with them using Ansible. What more could we ask for?
As a side note, having looked at the well-documented repositories used to construct both boxes, I may look at spinning forked copies which are prepared specifically for the hacklab to save some time at the Ansible stage.
To inform our virtualisation provider what machines we want and how to configure them, we need to use a Vagrantfile. As with the previous article, this is not a technical deep dive into understanding the technology so lets just have a look at the Vagrantfile I wrote.
"This is written for Hyper-V?! You said you'd do it in Virtualbox. You sit upon a throne of lies!"
Correct. My lab environment runs on a Hyper-V server so this is my working, tested Vagrantfile that I've used to deploy to my own infrastructure and that I know works. Fear not, however, as I will show you, with the magic of ~*~aNoThEr CoDe SnIpPeT~*~ how to configure it for Virtualbox. If you are using Hyper-V like me, you will note that the Virtualbox Vagrantfile specifies a network setting absent from the Hyper-V Vagrantfile. This is because Vagrant cannot (yet) manage Hyper-V network adapters. As such, when you launch the Vagrantfile, you will get an interactive prompt to select which interface you'd like to supply to the machine.
This Vagrantfile will configure the boxes similarly to the Hyper-V variant above. You can adjust the memory and CPU assignments to whatever fits best for your available resources. The workstation will run fairly with 2GB RAM and 1 CPU but the server will start to creak a little with less than 2 CPUs while 2GB memory will make it a little sluggish.
The Virtualbox configuration sets up both boxes on the host-only adapter but you can change these as you see fit. Take a look at HashiCorp's documentation for more guidance.
Invoking the Ansible playbook with Vagrant
The key benefit to nesting the Ansible playbook into the Vagrantfile is that we don't need to define an inventory or worry about authentication. Vagrant already has access to the machines and can execute the playbook based on the hostnames defined. We need to modify the playbook a little to integrate with Vagrant and to account for some differences between the standard ISO/VHD evaluation versions from Microsoft and the Vagrant boxes we're using to replace them.
Firstly, we're force-installing the DNS service because of some funkiness I ran into during the setup stages. We need it installed anyway so there's no redundant steps here and this ensures we get the services we need. Secondly, we're targeting Vagrant's dynamic Ansible inventory to get the IP addresses for setting DNS on both hosts. Lastly, we're disabling IPv6 because it is the devil's work and we don't abide by hexadecimal layer 3 addressing round these parts - we worship the dot-decimal notation and so should you.
As mentioned, we no longer need to define an inventory because Vagrant can execute the connection for us. We do, however, have to override its default connection type to make it use NTLM. Fortunately, we can do that in the same code block where we tell it to use our playbook. You need to add the following snippet inside the parent code block of the Vagrantfile from above (i.e. after the Vagrant.configure... line and before the last end).
If you insert the code block as-is, it will generally execute once per machine meaning that things will get double provisioned - which is absolutely fine. However, if we use a little conditional magic, we can make sure to invoke it only once. Stick the following code block in instead, as the last thing to be executed inside the config.vm.define opts["name"] do |machine| loop, and it will ensure the playbook is only executed after the workstation comes up, which will only be provisioned after the server is up.
You need to put the Vagrantfile and playbook.yml in the same directory or change the location directive (ansible.playbook = "playbook.yml").
You will need, obviously, to have installed Vagrant and Ansible on the host you're using to build the lab. The build can then be started by simply running vagrant up in the directory. If you have to re-run it due to any timeouts or non-blocking failures, you'll need to run the same command but include the --provision flag to ensure Ansible is executed again too - this also works if you want to apply changes you've made to the Ansible playbook post-deployment. If all goes well, you will end up with a fully configured hacklab ready to go. If you want to power the lab down, you can use vagrant halt, and if you want to scrub the lot, vagrant destroy.
Add some more users!
"I want more users to target, please."
Troubleshooting and errata
Once again, if you're having any kind of issues with the playbook or Vagrantfile or setting up either tool, give me a shout on Twitter @0x616e6874. I'll be happy to help get it sorted and, if it helps to improve this post, I'll give you a nod here too.
If you have no problems, I'm keen to hear about that too.