Adrian Cockroft Wants You to Run Gauntlt
Thanks to David Goehring for the base image CC BY 2.0
Secure APIs with a robust ruggedization framework
A few months ago Adrian Cockroft gave a keynote at devopsdays Amsterdam. In it, he recommended the use of Gauntlt. It’s a robust ruggedization framework for APIs. In plain English, Guantlt is an easy way to test for common security issues.
Have you started using Gauntlt yet? Me neither. Cockroft is sad. Let’s change that.
It turns out, Gauntlt is just the type of tool that IronWorker is great for. It’s modular, and easy to parallelize with the worker pattern. This post is a guide for getting your own Gauntlt up and running.
Bundle Some Dockers
To seed our efforts, we’ll use the handy iron-io/dockerworker repo on github. Start by opening a shell and cloning the repo:
git clone https://github.com/iron-io/dockerworker.git cd dockerworker/ruby
Before we can get to testing, we’ll need to vendor dependencies. It turns out, Nokogiri (a dependency of Gauntlt) is something of a problem child. We can fix that by modifying our usual docker workflow like so:
docker run --rm -v "$PWD":/worker -w /worker -e "NOKOGIRI_USE_SYSTEM_LIBRARIES=1" iron/ruby:dev sh -c 'bundle config --local build.nokogiri --use-system-libraries && bundle install --standalone --clean --binstubs'
Woo! there’s a lot more text there than usual. What’s going on? For old versions of Nokogiri, an environment variable is read (-e “NOKOGIRI_USE_SYSTEM_LIBRARIES=1”
). For new versions, the bundler flag --use-system-libraries
does the trick. We’re using both, in the hopes of future proofing this guide.
Tangentially, you may also notice that we’ve added the --binstubs
argument to our usual bundler flags. This tells bundler to make the gauntlt exe available in bin/gauntlt
. Useful if you find yourself wanting other Ruby executables in Docker!
Choose Your Weapon
Sweet! We should have an image ready for testing. Let’s pick a test target.
Gauntlt offers a number of choices in the GitHub repo under examples/. To keep things simple, I’ll demo with the verbs.attack file in examples/curl.
Here’s what’s inside:
Gauntlt uses Rspec and Cucumber to create snazzy BDD style test docs. That means some of our tests can double as documentation. Bonus!
The English-y looking language is Gherkin. This is the syntax Cucumber (and subsequently Gauntlt) use to spec tests. If you’re familiar with Markdown, then the pipe delimited tables and triple quoted escapes should seem familiar.
Draw a line from the tables to the <bracketed> statements, and you’ll see how this test works. The above spec will send nefarious HTTP requests to Google.com, and hopefully return a 405 (Method Not Allowed)
error.
We just need one more tweak. We’d like to be able to test many APIs, and many domains. I mean, yeah, we’ve got your back Google, but we’ve got our own testing to do, as well. To make that happen we’ll need to make a few tweaks.
Work It Out
IronWorker operates by passing messages. We send a message saying we want something done, and worker whirs to life. In the case of Gauntlt, it’s natural for each message to be the URI we’d like to test.
To make that work we’ll need to read the URI, and insert it into the verbs.attack file. Easy enough! Ruby comes with a simple embedding tool called ERB. Let’s open the verbs.attack file, and save it as verbs.erb.
Now, let’s make some modifications:
See the difference? We’ve added those funky <% %>
tags where we want our URI to appear.
Looking good, we’re almost done. Now we just need to head back to dockerworker/ruby
for two final tweaks.
The Final Countdown
Open up hello.rb
, and replace the contents with the following:
The above code takes the ERB file + the payload message, and builds a new verbs.attack. Once that’s finished, it executes the attack!
The last file we need to edit is hello.payload.json
. We’ll replace it’s contents with the following:
{ "marketing-site": "iron.io" }
Now we’re ready to test!
On your shell type out the usual DockerWorker test command:
docker run --rm -it -v "$PWD":/worker -w /worker -e "PAYLOAD_FILE=hello.payload.json" iron/ruby ruby hello.rb
Your terminal should return results that look something like:
Wait, error? Ugh. Looks like I’ll be chatting with our Ops team. It’s possible we’re happy with a 400 response code. In which case, I’ll modify verbs.erb
to expect that as the response.
Upload to Iron.io
The final step is to build a Docker image from your file, and push it to Docker. This is a new one if you’re accustomed to our usual Docker workflow. This is necessary since normal zipping removes file permissions.
In honor of Gauntlt’s medieval naming scheme I’m naming mine ‘Pauldrons’.
Docker build -t pauldrons .
Final bits are following Docker’s instructions for adding an image. Be sure to click that link, and follow the instructions. Once you’re done send it to iron.io:
iron worker upload --name pauldrons thatmightbepaul/pauldrons ruby hello.rb
Note: I chose pauldrons as both my Docker image name, and my ironWorker repository.
If you’re feeling really spunky, you can add a multicast push queue to trigger new test runs. This makes it really easy to add new tests. Build a new worker + test combination, add it as a subscriber, and boom! You’re the office hero for bringing rugged testing to the common folk.
As a final note, many of the tests in Gauntlt require special tools and languages. You can find most of the tools in the Gauntlt ready_to_rumble.sh script. For languages, you’ll want to layer on any extra’s (like say, Python) using Iron.io’s handy Dockers repo.