---
title: "Buildkite"
description: "Learn how to integrate StackHawk with Buildkite for continuous integration and delivery (CI/CD), ensuring automated security testing in your pipeline."
url: https://docs.stackhawk.com/integrations/ci-cd/buildkite/
---

# Buildkite

![Buildkite](https://docs.stackhawk.com/images/integrations/logos/buildkite.svg)

[Buildkite](https://buildkite.com/) 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](https://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.

- [Buildkite Agent](https://buildkite.com/docs/agent/v3/installation)
- `curl`, which the hawk CLI [install script](https://docs.stackhawk.com/stackhawk-cli/#install-with-a-script) uses to download HawkScan
- [Docker](https://docs.docker.com/get-docker/), to run the example apps and for the Docker alternatives
- [Docker Compose](https://docs.docker.com/compose/install/), for the Docker Compose example

## 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`. The `hawk` CLI reads its API key from `API_KEY` automatically.

For details on how to do this in Buildkite, check out their documentation on [managing pipeline secrets](https://buildkite.com/docs/pipelines/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](https://buildkite.com/docs/agent/v3/hooks#available-hooks) script. On an Ubuntu Buildkite agent host, you can use the following script saved at `/etc/buildkite-agent/hooks/environment`.

```shell title="/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:

```bash
buildkite-agent pipeline upload
```

Your New Pipeline configuration should look something like this.

![Create Pipeline](https://docs.stackhawk.com/images/integrations/cicd/buildkite/create-pipeline.png)

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 [example.com](https://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](https://app.stackhawk.com/applications) screen.

```yaml title="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 installs the latest HawkScan release with the install script and runs a scan using the HawkScan configuration above.

```yaml title=".buildkite/pipeline.yml"
steps:
  - label: "Run HawkScan"
    key: hawkscan-remote
    command: |
      # Optional: pin a version (6.0.0 or later). Leave it unset to install the latest release.
      # export HAWK_INSTALL_VERSION=6.6.0
      curl -fsSL https://download.stackhawk.com/hawk/install.sh | sh
      export PATH="$$HOME/.hawk/bin:$$PATH"
      hawk scan
```

The install script checks the download’s checksum and installs `hawk` to `~/.hawk/bin`. It doesn’t change the PATH, so the next line adds the install directory. Keep the install and the scan in the same `command`: each Buildkite step runs in a new shell, so a PATH change in one step doesn’t reach the next. The `$$` escapes stop Buildkite from interpolating `$HOME` and `$PATH` when it uploads the pipeline, so the shell expands them when the step runs.

To run HawkScan as a Docker container instead, replace the step with:

```yaml title=".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](https://app.stackhawk.com/scans) 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](https://app.stackhawk.com/applications) screen.

```yaml title="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, then install HawkScan and scan the application 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.

```yaml title=".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"

  - wait
  - label: "Run HawkScan"
    key: hawkscan-local
    command: |
      curl -fsSL https://download.stackhawk.com/hawk/install.sh | sh
      export PATH="$$HOME/.hawk/bin:$$PATH"
      hawk scan

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

Because the `hawk` CLI runs directly on the agent machine, it reaches the application at `localhost` with no extra network configuration. If you run HawkScan as a Docker container instead, give the container the host’s network with `--network host`:

```yaml title=".buildkite/pipeline.yml"
  - label: "Run HawkScan"
    key: hawkscan-local
    command: |
      docker run -v $(pwd):/hawk:rw -t \
        --network host \
        -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](https://app.stackhawk.com/scans) to review your scan details.

### Docker Compose Environment

[Docker Compose](https://docs.docker.com/compose/gettingstarted/) 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.

Publish your app’s port on the agent machine, and scan it there with the `hawk` CLI. In this example, we will scan an Nginx container named `nginx`, published on port 8080.

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

```yaml title="docker-compose.yml"
version: '3.7'

services:
  nginx:
    image: nginx
    ports:
      - 8080:80
    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](https://app.stackhawk.com/applications) screen.

```yaml title="stackhawk.yml"
app:
  applicationId: xxXXXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX
  env: Develop
  host: http://localhost:8080
```

Now create your Buildkite pipeline file, `.buildkite/pipeline.yml`. Configure it to start your Docker Compose configuration in the background, then install HawkScan and scan the published port.

```yaml title=".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"

  - wait
  - label: "Run HawkScan"
    key: hawkscan-compose
    command: |
      curl -fsSL https://download.stackhawk.com/hawk/install.sh | sh
      export PATH="$$HOME/.hawk/bin:$$PATH"
      hawk scan

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

Check those three 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](https://app.stackhawk.com/scans) to review your scan details.

#### Docker Alternative

You can also run HawkScan as a Docker container on the same bridge network as your app, and reach the app by its service name. Set `app.host` in `stackhawk.yml` to `http://nginx`, and replace the “Run HawkScan” step with:

```yaml title=".buildkite/pipeline.yml"
  - 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
```
