---
title: "Concourse CI"
description: "Integrate HawkScan DAST scanning into Concourse CI pipelines. Configure automated security testing with remote and local scanning options."
url: https://docs.stackhawk.com/integrations/ci-cd/concourse-ci/
---

# Concourse CI

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

HawkScan fits neatly into a [Concourse CI](https://concourse-ci.org/) pipeline, providing dynamic security scanning every time you commit code.

In this guide, we will describe a method to scan a publicly available example app. Then under [Local Scanning](#local-scanning), a method to run and test your app all within the Concourse CI build environment using Docker Compose.

Both approaches share the same high level steps:

1. Secure your API key as a secret credential.
2. Build out your Concourse pipeline configuration.
3. Configure HawkScan with a `stackhawk.yml` file.

## Secure Your API Key

When you signed up on StackHawk, you created an API key. To keep it secret, add it to your [credential management](https://concourse-ci.org/creds) for use in your Concourse pipeline. Concourse supports many types of credential stores. For our examples, we use [CredHub](https://docs.cloudfoundry.org/credhub/), and we store our key as `hawk_api_key`.

If you use CredHub, you can set your API key secret like so.

```shell
credhub set -n /concourse/main/hawk_api_key --type value --value "hawk.AAaaAAaaAAaaAAaaAAaa.BBbbBBbbBBbbBBbbBBbb"
```

## Build Your Pipeline

Construct a `ci/hawkscan-remote.yml` file in your repository to configure a Concourse pipeline to run HawkScan. This pipeline will have a single job, **hawkscan-remote**, which will perform the following tasks:

1. Fetch the code repository, which contains a HawkScan configuration file, `stackhawk.yml`.
2. Install the `hawk` CLI with the hawk CLI [install script](https://docs.stackhawk.com/stackhawk-cli/#install-with-a-script).
3. Run `hawk scan` using the `stackhawk.yml` configuration file found in your code repository.

Your file should look similar to this, substituting your own git repository for `examplecorp/example`:

```yaml title="ci/hawkscan-remote.yml"
resources:
  - name: example-repo
    type: git
    source:
      uri: https://github.com/examplecorp/example.git
jobs:
  - name: hawkscan-remote
    plan:
      - get: example-repo
        trigger: true
      - task: scan-remote
        config:
          platform: linux
          image_resource:
            type: registry-image
            source:
              repository: buildpack-deps
              tag: jammy-curl
          inputs:
            - name: example-repo
          params:
            API_KEY: ((hawk_api_key))
            # Optional: pin a version (6.0.0 or later). Leave it unset to install the latest release.
            # HAWK_INSTALL_VERSION: "6.6.0"
          run:
            path: bash
            args:
              - -ec
              - |
                curl -fsSL https://download.stackhawk.com/hawk/install.sh | sh
                export PATH="$HOME/.hawk/bin:$PATH"
                cd example-repo
                hawk scan
```

In this pipeline, we define one resource, **example-repo**, a GitHub repository which contains our HawkScan configuration. Typically, this would also contain the source code to be built, deployed, and tested. We define a single job, **hawkscan-remote**, which fetches **example-repo**, and then executes the **scan-remote** task. The **scan-remote** task runs in the `buildpack-deps:jammy-curl` image, a small Ubuntu image that includes `curl`. The `hawk` binary needs glibc, so use a Debian- or Ubuntu-based image rather than Alpine. The task sets the `API_KEY` parameter, which the `hawk` CLI uses to authenticate to the StackHawk platform to submit scan results. Finally, the **scan-remote** task runs a small inline script which installs the latest HawkScan release, adds its install directory to the PATH (the install script doesn’t change the PATH itself), and runs `hawk scan` from the repository directory.

### Docker Alternative

To run the scan in the HawkScan Docker image instead, use this pipeline. It fetches the `stackhawk/hawkscan` image as a resource and runs the scanner executable, `shawk`, inside it:

```yaml title="ci/hawkscan-remote.yml"
resources:
  - name: example-repo
    type: git
    source:
      uri: https://github.com/examplecorp/example.git
  - name: hawkscan
    type: docker-image
    source:
      repository: stackhawk/hawkscan
jobs:
  - name: hawkscan-remote
    plan:
      - in_parallel:
          - get: example-repo
            trigger: true
          - get: hawkscan
      - task: scan-remote
        image: hawkscan
        config:
          platform: linux
          inputs:
            - name: example-repo
          params:
            API_KEY: ((hawk_api_key))
            REPO_DIR: /home/steve/example-repo
          run:
            path: bash
            args:
              - -exc
              - |
                cp -rp example-repo "${REPO_DIR}"
                cd "${REPO_DIR}"
                shawk
```

> *Pro Tip: The `REPO_DIR` variable tells HawkScan where to find your repository, and is set to the volume bind mount point, `/zap` (`/steve` as of `hawkscan 4.0.0`), by default. When you copy code directly into the container, this variable should be set to a directory under `/home/zap` (NOTE: `/home/steve` as of `hawkscan 4.0.0`).*

## Configure HawkScan

At the base directory of your code repository, create a `stackhawk.yml` appropriate for scanning your application. For our example, we will create a minimal configuration pointing to our `Development` environment API endpoint, [example.com](https://example.com).

```yaml title="stackhawk.yml"
app:
  applicationId: xxXXXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX
  host: http://example.com
  env: Development
```

Replace the value for `app.applicationId` with your Application ID from StackHawk, and set `app.env` to the environment name you prefer.

## Run It

Check those two files into source control, and push them to GitHub. Set your pipeline up with the `ci/hawkscan-remote.yml` file, like so:

```shell
fly --target KAAKAW set-pipeline --pipeline hawkscan-remote --config ci/hawkscan-remote.yml
```

## Head over to the Concourse CI console to watch your workflow run. When it is complete, check your account at StackHawk to review your scan details!

## Local Scanning

The previous example assumes that you have an integration environment that is publicly accessible. Alternatively, you can run your app and scan it directly on the ephemeral Concourse build container. A great way to do that is to assemble your application environment and HawkScan itself in a docker-compose file. This example uses the HawkScan Docker image, because the Docker Compose task image it runs in is based on Alpine Linux, where the `hawk` CLI can’t run.

### Docker Compose

For this run, we will simulate our app with a Nginx container named `nginx_test`, and run HawkScan against it on the bridge network, `scan_net`. We save this configuration at the base of our repository. Our configuration looks like this:

```yaml title="docker-compose.yml"
version: "3"
services:
  # Fire up the app to test, nginx_test
  nginx_test:
    image: nginx
    networks:
      - scan_net
  # Fire up HawkScan and scan the test app (nginx_test)
  hawkscan:
    image: stackhawk/hawkscan
    environment:
      API_KEY: ${API_KEY}
    volumes:
      - type: bind
        source: .
        target: /hawk
    tty: true
    networks:
      - scan_net
    depends_on:
      - nginx_test
# Make a network on which to run the scan
networks:
  scan_net:
```

Note that the `hawkscan` service depends on `nginx_test`, to ensure the application is running before the scan begins.

### Pipeline Configuration

Next, we set up the pipeline file, `ci/hawkscan-local.yml`. This time, we will run our job task in the [karlkfi/concourse-dcind](https://hub.docker.com/r/karlkfi/concourse-dcind) container, which has been tuned specifically for making it easy to run Docker Compose in a Concourse workflow.

```yaml title="ci/hawkscan-local.yml"
resources:
  - name: example-repo
    type: git
    source:
      uri: https://github.com/examplecorp/example.git
  - name: docker-compose
    type: docker-image
    source:
      repository: karlkfi/concourse-dcind
jobs:
  - name: hawkscan-local
    plan:
      - in_parallel:
          - get: example-repo
            trigger: true
          - get: docker-compose
      - task: scan-local
        privileged: true
        image: docker-compose
        config:
          platform: linux
          inputs:
            - name: example-repo
          params:
            API_KEY: ((hawk_api_key))
          run:
            path: entrypoint.sh
            args:
              - bash
              - -ceux
              - |
                cd example-repo
                docker-compose up --abort-on-container-exit
                docker-compose down
```

We provide a single parameter, `API_KEY`, which is passed to the HawkScan container via Docker Compose. Finally, we run a short inline script that sets our working directory to the cloned repository, runs our `docker-compose.yml` script, and then cleans up after itself. Note the command `docker-compose up`. We add the `--abort-on-container-exit` flag to tell Docker Compose to tear down the composition if a container stops. That way, when HawkScan is finished, the other containers will stop too, and the script will move on to clean up with `docker-compose down`.

### HawkScan configuration

The HawkScan configuration looks almost the same as before, except that now our target host is `nginx_test`, the name of the application to be scanned in `docker-compose.yml`.

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

Give it a run and check out your results. This is a great way to build out arrangements of containers for integration testing directly within the Concourse build environment, adding databases, tiers, and other microservices as needed!
