Firewall Testing With Docker

Historically new firewall rules have been tested manually by engineers SSHing into a VM or physical server and running netcat. This is slow and error prone, but well understood. New cloud and container platforms mean you can’t SSH into these servers any more, you need to create a container and do your testing from there. This makes manual testing even more annoying, but the whole point of cloud and container platforms is that they are designed to be highly automated. So lets build something that will run some well maintained tests in a Docker container.

Chef have a server testing framework called Inspec which is designed for testing the results of configuration management tools on a server. But it can also be used to test basic network connectivity, with two resources being particularly useful here - http and host; this allows us to test http requests and tcp connections with netcat.

Chef already provide a Docker image for Inspec chef/inspec but it doesn’t include netcat, which means the host resource doesn’t work. This is easily fixed by building upon this image to create the new image kaerast/inspecnc:

FROM chef/inspec
RUN apk add --update netcat-openbsd

We also wrote an example test suite to go with this for demonstration purposes:

control "example" do
  impact 1.0
  title "Example Webserver"
  desc "Example server should be available"
  describe host('', port: 80) do
    it { should be_reachable }
  describe http('') do
    its('status') { should eq 200 }

We can now test connectivity from within Docker:

docker run -it --rm -v $(pwd):/share kaerast/inspecnc exec example_spec.rb

However, the original problem was that we can’t actually ssh into the servers running Docker. So we can’t provide Inspec tests in the form of a local file mounted in a Docker volume. We then discussed the pros and cons of storing the data in an S3 bucket (easy to code, security might not like this data being stored in the cloud, not everywhere will have connectivity to S3) vs in a git repository (more likely to have network connectivity, security happier, harder to test offline, need to manage ssh keys). Since the initial goal is purely to demonstrate that this works we opted for pulling the tests from an http endpoint - which could be an S3 bucket, or it could be a local webserver.

So lets build a Dockerfile based on the one we already have that can pull the tests from an http endpoint provided as an environment variable:

FROM kaerast/inspecnc
RUN apk add --update wget
ENTRYPOINT wget $INSPEC_URL -O /share/1_spec.rb && inspec exec 1_spec.rb

We’ve built and published this as kaerast/inspec-from-http.

To test locally, we can start a simple HTTP server from the current directory with python -m SimpleHTTPServer which starts an HTTP server on port 8000.

And finally, we can now run Inspec tests from a Docker image with:

docker run -e INSPEC_URL= kaerast/inspec-from-http

Like most of the things I build, this is not production ready. We should build a version which loads data from Git, we should build an internal Rancher catalog item around it, integrate with the rancher-cli tooling, and automate the heck out of this. However, this is enough to get some engineers going in the right direction with the rest of these tasks.