Building DevSecOps Pipeline using Snyk, ZAP in Local Environment

Mohamed Fourti
6 min readJan 7, 2024

--

DevSecOps is an approach to software development that integrates security throughout the entire process, from design to operations to production. This article aims to guide you in building a DevSecOps pipeline directly from your development environment. We will leverage powerful tools like Snyk, and ZAP Proxy to scan our project.

Note: If you haven’t already, I recommend checking out my previous 3-part series on “implementing GitLab CI/CD in a Local Environment” As I used that environment during this article.

1-Setting Up the DVWA Repository:

For our project, we will be using “DAMN VULNERABLE WEB APPLICATION” a web application that is full of vulnerable, the perfect test subject!

We will start by cloning the repo found in DVWA. Next, we create a new repository in Gitlab and we push the downloaded repo.

cd existing_folder
git init --initial-branch=main
git remote add origin http://GitLab-Ip/project/dvwa
git add .
git commit -m "Initial commit"
git push --set-upstream origin main

Alternatively, you can import the project directly from GitHub after forking it!

Import the project directly from GitHub

Now that we have our repository set up, we can move on to the next step.

Our repo is created and ready

2-Creating our Pipeline

In this step, we will create a pipeline with four stages:

  • Build/Push: Construct a Docker image for the application and push it to DockerHub.
  • Snyk scan: Hunt for vulnerabilities in the built image.
  • Deploy: Launch the application using Docker Compose.
  • ZAP scan: Perform dynamic security scanning on the deployed application.

I won’t go into detail about the Build/Push and Deploy stages since I covered them in the third part of my previous article.

Build/Deploy Stage:

build:
stage: build
image: docker:latest
services:
- docker:dind
before_script:
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
script:
- echo "Building Docker image..."
- docker version
- docker build --tag mohamedfourti/dvwa:$CI_COMMIT_REF_NAME -f Dockerfile .
- docker push mohamedfourti/dvwa:$CI_COMMIT_REF_NAME
tags:
- manager
artifacts:
paths:
- docker-image/

Snyk Scan Stage:

Now that we have our image, we can proceed to the second stage, where we will scan it using Snyk.

Snyk is a powerful tool for vulnerability scanning, covering everything from insecure application code to runtime misconfigurations and network threats.

snyk_scan:
stage: snyk_scan
image: docker:latest
services:
- docker:dind
script:
- echo "Running Snyk vulnerability scan..."
- docker run -d --name snyk-container -v /var/run/docker.sock:/var/run/docker.sock snyk/snyk:docker sleep infinity
- docker exec snyk-container snyk auth $SNYK_TOKEN
- docker exec snyk-container snyk test --docker mohamedfourti/dvwa:$CI_COMMIT_REF_NAME --json > snyk_report.json || true
- docker rm -f snyk-container
tags:
- manager
artifacts:
paths:
- snyk_report.json

To perform a scan with Snyk in a local environment, we need to make a few adjustments. Instead of using Snyk integrations like GitLab, GitHub, BitBucket, or Jenkins, we will create a container using the official Snyk docker image. After authenticating with our Snyk.io account’s token using the command “snyk auth”, we can initiate the scan with the “snyk test” command.
The output will be saved as a JSON file, and by adding “true” at the end, our pipeline will continue to the next stage even if vulnerabilities are found (For demonstration purposes). Finally, we remove the container and save the report as an artifact for future reference.

Deploy Stage:

The DVWA repository provides its own compose files, which we will use to deploy the containers.

deploy:
stage: deploy
image: docker:latest
services:
- docker:dind
before_script:
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
script:
- echo "Deploying services using docker-compose..."
- docker pull mohamedfourti/dvwa:$CI_COMMIT_REF_NAME
- docker stack deploy -c compose.yml $CI_PROJECT_NAME
tags:
- manager

We can access the DVWA page using the Swarm IP and Port we defined in the compose file.

DVWA Login page

Zap Scan Stage:

After successfully deploying our container, it is now considered a live production website that can be accessed. Our next step involves conducting a penetration test using ZAP, a reliable and free open-source penetration testing tool.

ZAP enables us to scan for common vulnerabilities found in web applications, including SQL injection and cross-site scripting.

zap_scan:
stage: zap_scan
image: docker:latest
services:
- docker:dind
script:
- echo "Running OWASP ZAP security scan..."
- docker run --name zap -p 8090:8090 -i softwaresecurityproject/zap-bare zap.sh -cmd -port 8090 -quickurl http://Website-Ip:Port -quickout /zap/zap-report.html
- docker cp zap:/zap/zap-report.html $CI_PROJECT_DIR/zap-report.html
- docker rm -f zap
tags:
- manager
artifacts:
paths:
- zap-report.html

Similar to our approach with Snyk, we will be creating a temp container to perform the scan. Also, we will be using the “zap-bare” image version instead of the resource-intensive normal version to prevent any potential crashes of the virtual machine (Note that this will limit the test results).

In the initial steps of our script, we create a container and configure the port to 8090 (as opposed to the default port 8080, which was already occupied by another container). We then used the “-port” command to notify ZAP about the port change. Additionally, we provide the target IP using the “-quickurl” parameter. Lastly, we export the scan report using the “-quickout” option.

In the next step of our script, we copy the generated report from the container to the project directory, saving it as an artifact for further analysis.

To conclude the zap_scan stage, we ensure the container is removed to maintain system cleanliness and efficiency.

3-Testing the pipeline:

With the completion of our pipeline, we are now ready to initiate it. Assuming all goes smoothly, all stages should be executed and marked as passed. It is important to note that both Scan stages may require some time to execute, especially the ZAP scan, as it tends to consume system resources.

We can navigate to the job page for both the Snyk and ZAP stages to access and download the artifacts.

ZAP job page

For Snyk, the report will be saved in JSON format making it harder to read. So I recommend using snyk-to-html plugin to convert it to HTML for an easier read, more about the plugin on this page “Snyk-to-HTML”.

Converting the report JSON file to HTML

By converting the report to HTML, we can analyze its contents better.

Snyk Report

Conversely, the ZAP report is already in HTML format, so we simply need to download it from the artifact page

ZAP Report

Conclusion:

This DevSecOps pipeline effectively uses Snyk, ZAP, and CI/CD to conduct thorough scanning for your project’s security. By automating security checks early in the development process, you can proactively address vulnerabilities and establish software that is trustworthy for your users. In the next article, I will dive into Grafana and Prometheus, which will provide detailed insights into the performance, health, and resource utilization of our containers.

The full pipeline can be found here: Pastebin
Thank you for reading!

--

--