HawkScan and Buildkite

Buildkite

Buildkite is a great platform for building, testing, and deploying software. The straightforward YAML pipeline configuration language makes it easy to add StackHawk application security scanning.

In this how-to, we will describe the simple scenario of scanning a publicly available example app, example.com. Then we will show how to scan a service running on the localhost address, and finally how to scan a service in a Docker Compose configuration.

Prerequisites

The pipeline examples in this document were tested on an Ubuntu 20.04 server with the following software installed.

Protect Your API Key

HawkScan will need your StackHawk API key to send results back to the platform. Take care to protect your API key from accidental disclosure by saving it as a secret and exposing it in your pipeline as an environment variable, API_KEY.

For details on how to do this in Buildkite, check out their documentation on managing pipeline secrets.

We recommend using a dedicated secrets management system like AWS Secrets Manager, or Hashicorp Vault. But for testing, you can stash your API key in a Buildkite environment hook script. On an Ubuntu Buildkite agent host, you can use the following script saved at /etc/buildkite-agent/hooks/environment.

/etc/buildkite-agent/hooks/environment

#!/usr/bin/env bash
set -euo pipefail
export API_KEY="hawk.xxXXxXXxXxxxXXXxxXxx.xxxxXXxXXxXxxxXXXxxX"

Create a new pipeline

To follow along with these examples, set up a new repository in GitHub. Then create a new Buildkite pipeline, and connect it to your new repository.

In your New Pipeline setup, under build steps to run, add only:

buildkite-agent pipeline upload

Your New Pipeline configuration should look something like this.

  Create Pipeline  

Click Create Pipeline to continue.

If prompted, follow the instructions to set up a webhook from GitHub to Buildkite.

Now that your pipeline has been configured in Buildkite, let’s move on to configuring your StackHawk configuration and Buildkite pipeline YAML in your repository.

Scanning Scenarios

In order to scan your application in a Buildkite pipeline, you will want to deploy it after building so that HawkScan can reach it.

You could deploy your app to a remote environment such as a server instance or Kubernetes cluster. Or you could run it locally, on the same machine as your Buildkite agent where the pipeline runs. Or you could run it locally in a Docker Compose configuration, to make it easy to add any required services such as a database.

Here is how you can scan in each of those scenarios.

Remote Integration Environment

If your application is deployed to a remote environment, the scanning portion of your pipeline is pretty simple. You just point HawkScan at the endpoint and scan. In our example, we will scan the public website http://example.com.

Create a StackHawk configuration file. At the root of your repository, create the file stackhawk.yml. Add the following contents, replacing the value for app.applicationId with your own application ID from the StackHawk Applications screen.

stackhawk.yml

app:
  applicationId: xxXXXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX
  env: Develop
  host: http://example.com

Now create your pipeline configuration file, .buildkite/pipeline.yml. It will pull the latest version of the stackhawk/hawkscan Docker image, and run it using the HawkScan configuration above.

.buildkite/pipeline.yml

steps:
  - command: "docker pull stackhawk/hawkscan"
    label: "Pull the latest version of HawkScan"

  - wait
  - label: "Run HawkScan"
    key: hawkscan-remote
    command: |
      docker run -v $(pwd):/hawk:rw -t \
        -e API_KEY \
        stackhawk/hawkscan

Check those two files into source control, and push them to GitHub. Head over to the Buildkite console to watch your pipeline run. When it is complete, check your account at StackHawk to review your scan details.

Localhost Environment

In this example we will deploy our application locally, on the Buildkite agent machine. In the Buildkite pipeline, we will simply point HawkScan at the localhost address and scan.

For our example app, we will use a Dockerized version of Nginx listening on port 8080. Your service doesn’t have to run in Docker. It only needs to be reachable at the localhost address for this method to work.

At the root of your repository, create a stackhawk.yml file with the following contents, replacing the value for app.applicationId with your own application ID from the StackHawk Applications screen.

stackhawk.yml

app:
  applicationId: xxXXXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX
  env: Develop
  host: http://localhost:8080

Create your pipeline file, .buildkite/pipeline.yml. Configure it to start your application in the background, pull the latest version of the stackhawk/hawkscan Docker image, and run it using the configuration above. It’s a good idea to shut the application down when the scan is done, so it’s not hanging around to interfere with future builds.

.buildkite/pipeline.yml

steps:
  - command: "docker stop nginx || echo Nevermind"
    label: "Stop Nginx if it's already running"

  - wait
  - command: "docker run --detach --rm --publish 8080:80 --name nginx nginx"
    label: "Run Nginx"
  - command: "docker pull stackhawk/hawkscan"
    label: "Pull the latest HawkScan image"

  - wait
  - label: "Run HawkScan"
    key: hawkscan-local
    command: |
      docker run -v $(pwd):/hawk:rw -t \
        --network host \
        -e API_KEY \
        stackhawk/hawkscan

  - wait
  - label: "Stop Nginx"
    command: docker stop nginx

Check those two files into source control, and push them to GitHub. Head over to the Buildkite console to watch your pipeline run. When it is complete, check your account at StackHawk to review your scan details.

Docker Compose Environment

Docker Compose is a great way to set up a fully containerized local integration testing environment. You can run your own containerized app, along with any other requisite services such as databases.

In Docker Compose, your app and any other required services run on a bridge network. You can run HawkScan on the same bridge network, and reach your app by its service name. In this example, we will scan an Nginx container named nginx, running on the named bridge network, nginet.

At the root of your repository, create a docker-compose.yml file with the following contents to define your bridge network and Nginx service.

docker-compose.yml

version: '3.7'

services:
  nginx:
    image: nginx
    networks:
      nginet:

networks:
  nginet:
    name: nginet

Create a stackhawk.yml file with the following contents, replacing the value for app.applicationId with your own application ID from the StackHawk Applications screen.

stackhawk.yml

app:
  applicationId: xxXXXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX
  env: Develop
  host: http://nginx

Now create your Buildkite pipeline file, .buildkite/pipeline.yml. Configure it to start your Docker Compose configuration in the background, pull the latest version of the stackhawk/hawkscan Docker image, and run it using the configuration above.

.buildkite/pipeline.yml

steps:
  - command: "docker-compose down"
    label: "Stop service if it's already running"

  - wait
  - command: "docker-compose up --build --detach"
    label: "Service up"
  - command: "docker pull stackhawk/hawkscan"
    label: "Pull HawkScan image"

  - wait
  - label: "Run HawkScan"
    key: hawkscan-compose
    command: |
      docker run -v $(pwd):/hawk:rw -t \
        --network nginet \
        -e API_KEY \
        stackhawk/hawkscan

  - wait
  - label: "Service down"
    command: docker-compose down

Check those two files into source control, and push them to GitHub. Head over to the Buildkite console to watch your pipeline run. When it is complete, check your account at StackHawk to review your scan details.