HawkScan and Concourse CI

HawkScan fits neatly into a Concourse CI 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, 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 for use in your Concourse pipeline. Concourse supports many types of credential stores. For our examples, we use CredHub, and we store our key as hawk_api_key.

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

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. Fetch the HawkScan container image, stackhawk/hawkscan, for running tasks.
  3. Run the HawkScan command, shawk, 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:

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: stackhawk
      - task: scan-remote
        image: hawkscan
        config:
          platform: linux
          inputs:
            - name: example-repo
          params:
            API_KEY: ((hawk_api_key))
            REPO_DIR: /home/zap/example-repo
          run:
            path: bash
            args:
              - -exc
              - |
                cp -rp example-repo "${REPO_DIR}"
                cd "${REPO_DIR}"
                shawk

In this pipeline, we define two resources:

  • example-repo, a GitHub repository which contains our HawkScan configuration. Typically, this would also contain the source code to be built, deployed, and tested.
  • hawkscan - the StackHawk HawkScan Docker image. We define a single job, hawkscan-remote, which fetches example-repo and hawkscan, and then executes the scan-remote task. The scan-remote task sets two parameters, API_KEY and REPO_DIR. The HawkScan container uses API_KEY to authenticate to the StackHawk platform to submit scan results. It uses REPO_DIR to set the working directory for running scans. Finally, the scan-remote task runs a small inline script which copies example-repo to REPO_DIR, sets the working directory, and runs the scanner executable, shawk.

    Pro Tip: The REPO_DIR variable tells HawkScan where to find your repository, and is set to the volume bind mount point, /zap, by default. When you copy code directly into the container, this variable should be set to a directory under /home/zap.

    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, http://example.com.

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:

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.

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:

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 container, which has been tuned specifically for making it easy to run Docker Compose in a Concourse workflow.

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.

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!