Skip to content

Instantly share code, notes, and snippets.

@InfoSec812
Last active June 12, 2019 18:11
Show Gist options
  • Save InfoSec812/62ed5438ad218f734d230e222f1bc05f to your computer and use it in GitHub Desktop.
Save InfoSec812/62ed5438ad218f734d230e222f1bc05f to your computer and use it in GitHub Desktop.
Using A Multi Container Pipeline For Running Zed Attack Proxy

Overview

Leveraging a multi-container Pod in Jenkins means that we can use external tools like OWASP Zed Attack Proxy. Instead of installing ZAP into each and every potential Jenkins agent container (Maven, Gradle, NPM, etc...), we can use the sidecar pattern to run ZAP alongside whatever build container we would normally used without any changes.

Background

The goal of achieving continuous deployment/delivery is one which many feel uncomfortable with. How can we be assured that the product which is being deployed meets our standards for quality, reliability, and (sometimes most importantly) security? Each stage we add to a CI/CD pipeline is intended to give use further comfort and assurance that our deployed release is up to those standards; but how can we ensure that we are doing all that is needed to analyze for security vulnerabilities? Enter OWASP Zed Attack Proxy, which as it's name suggests is an HTTP Proxy server which also analyzes all requests which pass through for a multitude of security threats. In addition, it can be made to perform various attacks against the target application so that we can be assured that our applications are able to withstand the onslaught of malicious actions on the Internet. In this session, we will show how you can deploy ZAP in OpenShift, integration ZAP with Jenkins (or other) pipelines, capture reports, configure custom attacks and break the pipeline in case standards are not met.

Pre-requisites

How To Configure Multiple Containers

  1. A running OpenShift cluster with access to the Internet (By default, though it can be reconfigured to work in a disconnected environment)
  2. A ZAP Jenkins Agent built in OpenShift
  3. A build container for the appropriate project (Maven, NPM, etc...)

How To

Once you have used the instructions for setting up the multiple containers in the Jenkins pipeline script, you can then use the stages shown below to integrate ZAP

stage('Integration And Penetration Testing') {
  parallel {                                      // <1>
    stage('Start ZAP') {
      options {
        timeout(time: 10, unit: 'MINUTES')
      }
      steps {
        container('jenkins-slave-zap') {
          dir('/tmp/workspace') {
            sh returnStatus: true, script: '/zap/zap.sh -daemon -host 0.0.0.0 -port 9080 -config api.addrs.addr.name=.* -config api.addrs.addr.regex=true -config api.disablekey=true'
          }
        }
      }
    }

    // Implement stage to run Integration Tests Here
    stage('Integration/Acceptance Tests') {
      steps {
        script {
          def testApiHost = ""
          openshift.withCluster() {               // <2>
            openshift.withProject(env.TEST) {
              def routeDef = openshift.selector("route", env.APP_NAME).object()
              testApiHost = "${routeDef.spec.host}"
            }
          }
          retry(10) {                             // <3>
            sleep 5
            sh 'curl -s http://127.0.0.1:9080/JSON/core/view/mode'
          }
          dir(".mvn") {                           // <4>
            sh "echo '-Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=9080' > jvm.config"
          }
          def jsonReport = "{}"
          withEnv([ "INTEGRATION_TEST_HOST=http://${testApiHost}/v1"]) {
            try {                                 // <5>
              sh 'mvn -T 1.5C -Pintegration-testing failsafe:integration-test failsafe:verify'
              sh 'mkdir zap-report'
            } catch (Exception e) {
              throw e
            } finally {
              // Shut down ZAP and capture reports
              sleep 5
              sh 'curl -v -o ./zap-report/zap-report.html http://127.0.0.1:9080/OTHER/core/other/htmlreport'
              jsonReport = sh(returnStdout: true, script: 'curl http://127.0.0.1:9080/OTHER/core/other/jsonreport')
              sh 'curl http://127.0.0.1:9080/JSON/core/action/shutdown'
              dir(".mvn") {
                sh "rm -f jvm.config"
              }
            }
          }
                                                  // <6>
          def jsonData = new JsonSlurper().parseText(jsonReport)
          def highCriticalRisks = jsonData.site.each { site ->
            site.alerts.each { alert ->
              def alertValue = alert.riskcode as Integer
              if (alertValue >= 3) {
                error 'High/Critical Risks Detected By Zed Attack Proxy'
              }
            }
          }
        }
      }
    }
  }
}

// ... SNIP

post {
  always {                                        // <7>
    // publish ZAP report
    publishHTML(target: [
        reportDir            : "zap-report",
        reportFiles          : 'zap-report.html',
        reportName           : 'Zed Attack Proxy Penetration Testing Report',
        keepAll              : true,
        alwaysLinkToLastBuild: true,
        allowMissing         : true
    ])
  }
}

  1. Run the stages in parallel so that ZAP will come up and stay running while the intergration tests run
  2. Get the URL for the integration test target using the OpenShift DSL
  3. Wait for ZAP to start and be ready for processing before starting the integration tests
  4. Set up a Maven JVM config file so that the proxy properties can be set for the JVM
    • This can be customized for other build systems like NPM or use the Linux proxy environment variables
  5. Run the integration tests inside a try/catch/finally so that in case of failure the ZAP instance can be shut down
  6. Process the JSON results from ZAP in order to determine the levels issues detected and fail the build if the level is above the desired threshold
  7. In a post block under the always section, use the publishHTML plugin to publish the report as a Jenkins artifact.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment