Ensuring Web Security via Ansible (Apache)


NOTE: even though this will require Ansible, you can run this on any operating system contrary to Ansible typically only being run on Linux.  This is because everything is self-contained inside the Vagrant box and doesn’t require local installation of tools.

Overview

So, we’ve recently been talking about how you can increase your security with HTTP Security Headers.  Now I’m going to talk about why it’s important to automate the deployment of the aforementioned headers and how to automate it.  One of the most difficult things in life (not even just security) can be consistency, and using tools that helpfully ensure consistency can make your life easier and more secure.

Why is automation important?

While I’d love to talk about this topic for pages (because I LOVE automation 🤖😁), I’ll try and keep this as succinct as possible.  The biggest reason for automating anything, in my opinion, is to help remove human error from processes and also to enable humans to focus on more interesting/important tasks instead of the same monotonous ones.  There is a whole slew of other reason as well (i.e. compliance - by validating security checks ), but especially with today’s climate of “Move fast and break things” (reference). It’s nice to the guardrails of automation to help you, and not hurt yourself too badly because you’re moving so fast 😅.

 

One thing that I’ve always been a huge proponent of, is automating the provisioning of servers.  This is a huge time sink for system administrators (sysadmins), and valuable hours that could be better spent using the sysadmin’s skills.  There is always a tradeoff between the time/complexity of automating it and if it’s worth it vs the needs of the business, but that’s extremely contextual.  So, for today we’re going to proceed under the assumption it’s worth automating this problem.

 

Overall though, automation is quintessential to ensuring that things are acted upon in a consistent manner.  One important concept, that the tool I’ll be using for the automation talks about, is idempotency which can be summarized as “if you do something, it should consistently return the same result” (think functional programming).  We’ll be using this concept in our automation to ensure that we consistently get the same results from applying our automation, even if we run it 1,000 times it should always do the same thing.

 

Example automation with Security Headers

So, now that we know why it’s important and the general principles of automation we’ll start to get into the fun technical stuff! 😁

 

Just to outline what we’re going to be doing:

  1. Install Vagrant and necessary hypervisor - windows guide below, but other OS guides here (we won’t be doing a walkthrough)
  2. Starting Vagrant box + Apache without security provisioning
  3. Look at the web server without the security header
  4. Add security headers
  5. Look at the web server with the security headers applied

 

Now would be the time that you’d install Vagrant and VirtualBox (or your hypervisor of choice) from the videos linked above.  After you’ve done that, you’re now ready to start up the Vagrant box we’ll be using during this post.  Navigate to here in your browser: https://github.com/ProfessionallyEvil/blog-ansible-webservers

 

Then download the repo by clicking the “Code” button and then clicking “Download ZIP” as the picture shows below.

 

Once you’ve downloaded the zip, extract it, then open your terminal (PowerShell, cmd, or *nix terminal) and navigate to that directory, and finally go to the sub-folder of “apache”.

 

After you get inside the folder you can run the “vagrant up” command.  That’ll startup the Vagrant box (VM) as well as provision it automatically with a base Apache configuration.  You should see something similar to the screenshot below, but your screen will probably say that it’s downloading the Vagrant box first.

 

Below is the expected output if everything is successfully completed, and you’ll be back at your terminal prompt.

 

Next we can run the command “vagrant ssh”, and this’ll connect us to the VM via an SSH connection.  Now if you run the following command: “curl -I 127.0.0.1”, then you should see something like the picture below.

 

One thing of note is the “Server” header, we consistently tell clients to disable/remove that header when they have a server exposed to the internet.  While it’s technically security through obscurity, it’s at least another layer between you and the lowest hanging fruit in the security world.

 

While using Curl is nice to see the headers of the website, I’ve also automatically port-forwarded the same port 80 to your host’s port 8080.  So, you should be able to navigate to http://127.0.0.1:8080 and that should show you the web-page.

 

Next we’ll apply the security headers to the web server via Ansible.  First, exit out of the ssh session (you can do so by typing the word “exit” and hitting enter), and you’ll run this command: vagrant provision --provision-with security

 

This command runs another playbook that I’ve created to add a bunch of security headers, and if you were to ssh in again and run the Curl command (like before) then you should see something like the picture below.

 

The content security policy (CSP) was cut off, but you’ll see the whole thing on your screen.  Now if you navigate to the local site again in your browser, you should see that nothing appears to have changed, even though we significantly improved the security of the web-server.

 

Feel free to look at the playbooks that I’ve made and use them as examples for when you want to do the same provisioning for your Apache web-server.  One thing we didn’t talk about today was TLS/SSL, and that’s because it caused excessive overhead to complete with this small local example.  In general though, using something like certbot via an Ansible role can help automate away your certificate needs after the initial setup.  Another thing of significant importance is that if you run the provision command for security 1000 times, you’ll still get the same result.  This helps to prevent configuration drift, but it doesn’t 100% eliminate it (a topic for another time).

 

While implementing security felt painless to you, because all you had to do was run one command and all the security was added.  Authoring Ansible security playbooks can take more time, especially if you want to do it idempotently, so consider this for when you create playbooks for your company and allocate the appropriate amount of time.  Overall though, eliminating human error and reducing the amount of time it takes to handle security for your servers via automation is worth it, at least in my book it is 😁

 

Congratulations, now go forth and enjoy automation 🤖🥳

 

Resources: