HawkScan and Spinnaker

This guide will show you how to run HawkScan in Spinnaker. We will build out a simple pipeline that deploys an API microservice, miniapi to your Kubernetes cluster and runs HawkScan against it.

To work through this guide, you will need a StackHawk account. You can sign up for a free Developer account here.

You will also need a Kubernetes cluster running Spinnaker. If you want an isolated test instance of Kubernetes and Spinnaker, try Minnaker. It’s what we used for our own testing.

Protect Your API Key

HawkScan will need your StackHawk API key to send results back to the platform. Use kubectl to store it as a Kubernetes secret.

kubectl create secret generic stackhawk-secrets \
  --from-literal=API_KEY='hawk.xXXxxXxxXXxxxXxxXxXx.xxxxXXxxXXXxxXXXXxXx'

Create the development Namespace in Kubernetes

We will deploy our app to the development namespace. Create it now with the following command.

kubectl create namespace development

Create a Git Repository

Create a GitHub repository to host your StackHawk configuration file. Normally this would be your application’s code repository. But for this guide, an otherwise empty repository is fine. For now, make this repository public so that the HawkScan pod can check it out without authentication. We won’t be storing any secret data in it.

Create a StackHawk configuration file, stackhawk.yml, at the root of your repository. Substitute your own StackHawk Application ID for app.applicationId. You can find your Application ID under Applications in the StackHawk platform.

stackhawk.yml

app:
  applicationId: xxXXXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX
  host: http://miniapi.development:5000
  env: Development

Commit your changes and push them to GitHub.


Build Your Pipeline

Create a new Application in Spinnaker called miniapi. Then create a new Pipeline for miniapi called miniapi-pipeline.

We will add two stages to miniapi-pipeline. The first will deploy the containerized miniapi app to the development namespace. The second will scan miniapi in the development namespace with HawkScan using the stackhawk.yml configuration file from your Git repository.

Stage 1: Deploy miniapi to Development

The first stage of your pipeline will launch a miniapi Deployment to the development namespace, and create a Service for it as well.

Add a new stage to miniapi-pipeline with the following configuration.

  • Type: Deploy (Manifest)
  • Stage Name:
  • Deploy (Manifest) Configuration:
    • Basic Settings:
      • Account: spinnaker (or whatever cluster you prefer)
      • Override Namespace: True
      • Namespace: development
    • Manifest Configuration:
      • Manifest Source: Text
      • Manifest:
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: miniapi
          spec:
            replicas: 1
            selector:
              matchLabels:
                app: miniapi
            template:
              metadata:
                labels:
                  app: miniapi
              spec:
                containers:
                  - image: 'zconger/miniapi:latest'
                    name: primary
                    ports:
                      - containerPort: 5000
          ---
          apiVersion: v1
          kind: Service
          metadata:
            name: miniapi
          spec:
            ports:
              - port: 5000
                protocol: TCP
                targetPort: 5000
            selector:
              app: miniapi
            type: LoadBalancer
        

Stage 2: Scan miniapi with HawkScan

Add a second stage with the following configuration.

  • Type: Run Job (Manifest)
  • Stage Name: HawkScan
  • Deploy (Manifest) Configuration:
    • Basic Settings:
      • Account: spinnaker (the same cluster as the first stage above)
    • Manifest Configuration:
      • Manifest Source: Text
      • Manifest:
          apiVersion: batch/v1
          kind: Job
          metadata:
            name: hawkscan
          spec:
            backoffLimit: 0
            template:
              spec:
                containers:
                  - command:
                    - /bin/bash
                    - '-c'
                    - |
                      git clone $REPO_URL $REPO_DIR
                      shawk
                    env:
                      - name: API_KEY
                        valueFrom:
                          secretKeyRef:
                            key: API_KEY
                            name: stackhawk-secrets
                      - name: REPO_DIR
                        value: /home/zap/workdir
                      - name: REPO_URL
                        value: 'https://github.com/<YOUR-ORG>/<YOUR-REPO>.git'
                    image: 'stackhawk/hawkscan:latest'
                    name: hawkscan
                restartPolicy: Never
            ttlSecondsAfterFinished: 600
        

Set the REPO_URL environment variable in the Job manifest above to the HTTPS URL for the git repository that contains your stackhawk.yml configuration file.

Pro Tip: For this guide, our git repository is public, so no authentication is necessary. For a private repository, you can inject an OAuth token into REPO_URL for authentication. In that case, REPO_URL should be stored as a Kubernetes secret.

Run That Pipeline!

Now start a manual pipeline execution in Spinnaker and watch your progress. If you check the console output from the HawkScan stage, the first message from the pod should be something like the following.

Cloning into '/home/zap/workdir'...

This indicates that the pod is working correctly and has cloned your Git repository. After a while you should see a summary of the scan results, like so.

StackHawk 🦅 HAWKSCAN - v0.8.30
* app id:              9e3a5594-0ec8-40f4-8ec7-48ef4442b767
* env:                 Development
* scan id:             fb1700b5-2c3e-4238-a8fe-d91a102ca371
* scan configs:        ['stackhawk.yml']
* app host:            http://miniapi.development:5000
* graphql:             False
Spider complete
Spider Crawled 3 URLs:
http://miniapi.development:5000
  http://miniapi.development:5000/robots.txt
  http://miniapi.development:5000/sitemap.xml
 Passive scanning progress 100%
Active Scan {'policy': 'c45e2369-6dd4-4b0f-bbd2-b9cc0c3cd228', 'target': 'http://miniapi.development:5000'} complete
Hawk Scanned 4 URLs:
  https://miniapi.development
  http://miniapi.development:5000
  http://miniapi.development:5000/robots.txt
  http://miniapi.development:5000/sitemap.xml
Uploading Logs Progress: 100%
Results for scan id fb1700b5-2c3e-4238-a8fe-d91a102ca371
Scan results for http://miniapi.development:5000
------------------------------------------------------------
Criticality: New/Triaged
   High: 0/0    Medium: 9/0    Low: 8/0 
------------------------------------------------------------
1) HTTP Only Site
   Risk: Medium 
   Cheatsheet: https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.md
   Paths (1):
     [New] GET 
2) Content Security Policy (CSP) Header Not Set
   Risk: Medium 
   References: https://developer.mozilla.org/en-US/docs/Web/Security/CSP/Introducing_Content_Security_Policy
               https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html
               http://www.w3.org/TR/CSP/
               http://w3c.github.io/webappsec/specs/content-security-policy/csp-specification.dev.html
               http://www.html5rocks.com/en/tutorials/security/content-security-policy/
               http://caniuse.com/#feat=contentsecuritypolicy
               http://content-security-policy.com/
   Paths (5):
     [New] GET 
     [New] GET /
     [New] GET /
     [New] GET /robots.txt
     [New] GET /sitemap.xml
3) X-Frame-Options Header Not Set
   Risk: Medium 
   References: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
   Paths (3):
     [New] GET 
     [New] GET /
     [New] GET /
4) Server Leaks Version Information via "Server" HTTP Response Header Field
   Risk: Low 
   References: http://httpd.apache.org/docs/current/mod/core.html#servertokens
               http://msdn.microsoft.com/en-us/library/ff648552.aspx#ht_urlscan_007
               http://blogs.msdn.com/b/varunm/archive/2013/04/23/remove-unwanted-http-response-headers.aspx
               http://www.troyhunt.com/2012/02/shhh-dont-let-your-response-headers.html
   Paths (5):
     [New] GET 
     [New] GET /
     [New] GET /
     [New] GET /robots.txt
     [New] GET /sitemap.xml
5) X-Content-Type-Options Header Missing
   Risk: Low 
   References: http://msdn.microsoft.com/en-us/library/ie/gg622941%2528v%3Dvs.85%2529.aspx
               https://owasp.org/www-community/Security_Headers
   Paths (3):
     [New] GET 
     [New] GET /
     [New] GET /
View on StackHawk platform: https://app.stackhawk.com/scans/fb1700b5-2c3e-4238-a8fe-d91a102ca371

Finally, check your scan results in the StackHawk app.


Where to go from here

This guide should give you a sense for how you can incorporate HawkScan into your Spinnaker pipelines. There is much more you can do from here to increase the depth of the scan and change the behavior of your pipeline based on your scan results.

From here you should consider some of these options for your scan configuration.