Quantcast
Channel: Mercy Bassey, Author at Simple Talk
Viewing all articles
Browse latest Browse all 5

Using Snyk for CI/CD Security Scanning

$
0
0

Security is important regardless of your industry, whether it’s finance, retail, e-commerce, or the broader world of IT. A little security oversight can have catastrophic impacts, leading to loss of money and unauthorized access to classified information.

It takes a lot of work to develop solutions that users trust. Therefore, you need to take security seriously to maintain the good reputation you have worked so hard for. In software delivery, security is as important as it is everywhere else.

Software delivery is part of the DevOps culture. When you take extra steps to integrate security, you are practicing DevSecOps. DevSecOps is still part of the DevOps culture but with an emphasis on “security.”

This article will introduce the concept of security scanning in detail, explain what it entails, how it can be incorporated into the DevOps culture, and explain how Snyk, a popular security tool, fits into security scanning. You’ll also see how to use Snyk in a CI/CD pipeline.

What is Security Scanning

Security scanning, also known as “vulnerability scanning,” involves analyzing a system to determine whether it is susceptible to attacks. In this case, a system can be a network, hardware, a server, a piece of software, a bunch of code, an entire codebase, an application, or essentially anything that can be exposed to security threats.

It should be taken seriously and conducted regularly to maintain system safety. Systems like servers will benefit from checking for server misconfigurations, weak permissions, unauthorized access, or suspicious activity from specific or ranges of IP addresses. Codebases will benefit from checking for insecure API usage, injection vulnerabilities, hard-coded secrets, XSS, SQL injection, and more.

A significant shift is happening in the Cybersecurity space. If you do not have a plan or proactive measures to ensure your system is protected against Cyber-attacks, you’re on a dangerous path. Classified information could easily get into the wrong hands, you’ll lose money, and you will experience reputational damage and operational disruptions.

What does Security Scanning in CI/CD Entail

Narrowing security scanning into CI/CD, which is a critical aspect of the DevOps culture, entails automatically ensuring the security of applications and infrastructure at every stage of development. Identifying vulnerabilities and addressing them continuously as new code and updates are deployed.

For instance, in the development stage (CI), security scanning will involve running tests, checking for vulnerabilities, analyzing dependencies, and automatically checking for security best practices. While in the deployment stage (CD), security scanning will involve validating infrastructure as code (IaC) configurations, scanning container images, and checking that the deployment environment is securely configured and that it adheres to compliance standards.

You’ll need to use tools that’ll help you detect security issues during different stages of your CI/CD pipeline, such as during builds, before deployment, and on pull requests for cases where sensitive changes (new dependencies, configurations, etc) are introduced from contributors.

What is Snyk

Synk is a security tool that helps you identify and fix vulnerabilities in your code. It serves as an assistant so that you can focus on building the core functionalities while it seamlessly handles the security aspect. Synk has a free version, as well as paid for different use cases, which you can see on their pricing page.

Snyk is categorized into Snyk code, Snyk open source, Snyk container, Snyk IaC, and Snyk AppRisk. Each of these categories works for specific use cases and does the following:

  • Snyk open source and Snyk code: Snyk open source checks open source libraries and dependencies for known vulnerabilities. Snyk code scans custom code and functions for security issues. You can grant Snyk access to your Git repository, whether it’s on GitHub, GitLab, or Bitbucket, to scan through; if it finds any security issue, it’ll create a pull request to fix it, which you can then review and merge if you choose to.
  • Snyk container: Snyk container is for Snyk’s container registry integrations. It features a complementary tool called Snyk CLI that you can use to scan container images for vulnerabilities before you deploy them. It also features source code management (SCM), whereby Snyk automatically detects Dockerfiles stored in Git repositories like GitHub, GitLab, or Bitbucket, scans the base image for vulnerabilities using Snyk open source, and recommends a secure or less vulnerable version.
  • Snyk IaC: For infrastructure engineers who provision cloud resources through code, Snyk IaC can identify and fix misconfigurations in infrastructure code. You can have Snyk scan infrastructure code within Terraform, CloudFormation, Helm charts, and ARM templates.
  • Snyk AppRisk: This category is for application security (AppSec) teams that want to manage and reduce application risk at scale. Snyk AppRisk, an application security posture management (ASPM) tool, provides insights into runtime behavior and spots application loopholes that attackers can exploit.

The IDE or text editor you use doesn’t matter; Snyk can be integrated into widely used IDEs and text editors like Vscode and Pycharm to provide real-time security checks and feedback directly in your development environment. Snyk can be used within CI/CD platforms like GitHub actions, Bitbucket pipelines, Circle CI, Travis CI, GitLab CI, Jenkins, and many others to automate security checks as part of your development lifecycle to help you catch and fix security issues early and reduce the risk of vulnerabilities making it to production.

Performed security scanning without Snyk

I have performed security scanning without Snyk, using npm audit (a command that scans project dependencies), and it was tedious. With the npm audit, I was able to generate a vulnerability report for my project and view their severity levels.

Checking for vulnerabilities with npm audit

Using the npm audit fix command, I was able to find and fix dependency vulnerabilities by upgrading to more secure ones, as recommended by the npm audit command.

Fixing vulnerabilities with npm audit fix

While the npm audit command helped, I just couldn’t do enough; npm audit only works for Node.js projects, which use npm as their package manager. I also couldn’t check my code for patterns that could cause security issues. And, in an era where programmers need to diversify when it comes to programming languages, npm audit isn’t language agnostic, which is a feature that contributed to its limitation.

Suppose I’m working on a Python, Java, Ruby, C++ project or any other programming language. In that case, I need to incorporate separate tools for vulnerability scanning and security checks. For instance, in a Python project, I could use pip-audit, for a Ruby project I could use bundle-audit, and so on.

These separate tools lack language-agnostic features, making managing security across diverse projects complex. Therefore, I don’t recommend using a language-specific tool for security scanning, but instead a robust, feature-rich, and sophisticated tool that integrates seamlessly with diverse ecosystems. Something that doesn’t just scan dependencies but can also scan custom code, that is, the one you wrote yourself.

Snyk supports popular programming languages like Python, JavaScript, Elixir, Rust, TypeScript, Dart/Flutter, and Go. The official documentation lists supported languages.

Performing security scanning with Snyk

The following sections will walk you through Snyk and how to use it to implement security scanning on a GitHub actions CI/CD pipeline. You’ll use the Snyk container to scan an Nginx image, Synk open source to scan open source libraries for a Django application, and Snyk code to scan the same Django application. This tutorial’s Django project is managed using Poetry version 1.8.5.

Prerequisites

To follow along, you are required to have the following in place:

Scaffolding an application

You’ll begin by using the Snyk container to demonstrate how to implement Snyk in a CI/CD pipeline. For the most part, you’ll use Snyk CLI to scan a Nginx container image. To begin, clone the following Git repository with this command:

git clone git@github.com:mercybassey/nginx-snyk-scaffolding.git

This will create a local copy of the repository on your machine. It contains a Dockerfile with a base image of nginx:1.17.0 exposed on port 80 and an index.html file that says “Hello Snyk.”

Scanning for Vulnerabilities in a Container Image

If you installed the Snyk extension for VScode, then the Snyk CLI is installed automatically. To confirm this, execute the command below to check the Snyk version.

snyk --version

Authenticate with the Snyk CLI using the following command:

snyk auth

This will open up a page on your default web browser where you must log in or sign up with GitHub, Google, BitBucket, Azure AD, or Docker ID. This article uses GitHub as the login option:

Signing up to Snyk.io with GitHub

Once you have successfully signed up and logged in, you must allow Snyk to authenticate your machine. Go ahead and authenticate. Once this process is successful, you should have the following image:

Authenticating with Snyk successfully

However, you still need to retrieve your authentication token to integrate Snyk with GitHub actions. This makes it possible to authenticate your GitHub actions pipeline with your Snyk account. Snyk stores your authentication token in the following file ~/.config/configstore/snyk.json; run this command to view your authentication token:

cat ~/.config/configstore/snyk.json

This will output your authentication token in the following format:

cat ~/.config/configstore/snyk.json
{
   "api": "fc37...."
}

Copy it and add it to your GitHub repository as a secret. See the following guide on adding secrets in a GitHub repository for GitHub actions if you don’t know how to do so already.

Alternatively, you can use this command to get your auth token:

snyk config get api

Head to your working directory, create a .github/workflows/ci.yml file, and paste in the following code, replacing <dockerhub-username> with your username on DockerHub:

Note: Naming your custom images using this format <dockerhub-username>/<image-name> makes pushing to your DockerHub repository easy.

name: Snyk Container Scan
on:
  push:
    branches:
      - main
jobs:
  snyk:
    runs-on: ubuntu-24.04
    steps:
      - name: Check out repository
        uses: actions/checkout@v2
      - name: Build Docker image
        run: docker build -t <dockerhub-username>/custom-nginx .
      - name: Run Snyk to check for vulnerabilities
        uses: snyk/actions/docker@master
        with:
          image: <dockerhub-username>/custom-nginx
          args: --file=Dockerfile --severity-threshold=high
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_AUTH_TOKEN }}

In the workflow above, GitHub Actions will automatically build the Docker image and then run Snyk to scan for vulnerabilities in the base image specified in the Dockerfile using the --file argument.

If there’s any issue with the base image, Snyk will report the vulnerabilities with high severity levels and above and recommend alternative base images, since it has access to the Dockerfile in this workflow.

Execute the Git commands below sequentially to trigger this workflow:

Replace <github-username> with your username on GitHub.

git init
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:<github-username>/nginx-snyk.git
git push -u origin main

Since the base image specified in the Dockerfile is outdated, you should see a ton of vulnerabilities with high and critical severity levels in your CI, specifically at the job “Run Snyk to check for vulnerabilities.” Because you have set the severity threshold to high and above, low and medium severity vulnerabilities will not be reported and thus, not trigger a failure in the CI process, though it’ll still be recorded.

In this example, Snyk has identified 248 vulnerabilities, with 27 critical, 44 high, 52 medium, and 125 low.

Base Image    Vulnerabilities      Severity nginx:1.17.0  248    27 critical, 44 high, 52 medium, 125 low

You should also see alternative base images that Snyk recommends, alongside the number of vulnerabilities detected and their levels.

Recommendations for base image upgrade:
Minor upgrades
Base Image   	            Vulnerabilities  	             Severity
nginx:1.26.2  		91               		             1 critical, 1 high, 1 medium, 88 low
Alternative image types
Base Image                  		Vulnerabilities             Severity
nginx:1.27.1-bookworm       		91              		1 critical, 1 high, 1 medium, 88 low
nginx:1.26.2-bookworm-perl  	91               		1 critical, 1 high, 1 medium, 88 low
nginx:stable-bookworm-perl  	91              		1 critical, 1 high, 1 medium, 88 low
nginx:1.27.1-bookworm-otel  	94             		1 critical, 1 high, 1 medium, 91 low

From the output above, Snyk recommends upgrading to nginx:1.26.2 or use the following alternatives – nginx:1.27.1-bookworm, nginx:1.26.2-bookworm-perl, nginx:stable-bookworm-perl or nginx:1.27.1-bookworm-otel .

Proceeding regardless of vulnerabilities

By design, Snyk will terminate a CI workflow if it finds any vulnerability, regardless of its severity level (low, medium, high, or critical). However, there’s something you should note: there’s no guarantee that official and latest Docker images have no vulnerabilities. There is always a possibility that even the most secure images may contain some vulnerabilities.

In this case, Snyk will not recommend any alternatives; however, it will still record the vulnerabilities it finds, inform you that you are using the most secure base image, and halt the CI process. Therefore, you have to explicitly tell Snyk to continue even if vulnerabilities are detected.

Head back to your project and use the nginx:1.27.1-bookworm as the base image in your Dockerfile, and edit the CI to look like the following:

name: Snyk Container Scan
on:
  push:
    branches:
      - main
jobs:
  snyk:
    runs-on: ubuntu-24.04
    steps:
      - name: Check out repository
        uses: actions/checkout@v2
      - name: Build Docker image
        run: docker build -t <dockerhub-username>/custom-nginx .
      - name: Run Snyk to check for vulnerabilities
        continue-on-error: true
        uses: snyk/actions/docker@master
        with:
          image: <dockerhub-username>/custom-nginx
          args: --file=Dockerfile
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_AUTH_TOKEN }}

From the CI above, the continue-on-error setting in the step “Run Snyk to check for vulnerabilities” allows it to proceed even if it finds vulnerabilities.

Commit and push these changes to your GitHub repository to trigger the workflow. You should have the CI run to completion.

Viewing CI on GitHub

Viewing Snyk scan results with GitHub Code Scanning

GitHub code scanning is a SaaS tool that is available on GitHub. While Snyk already outputs scan results in the CI workflow, it’s not the most accessible format for tracking and review in terms of vulnerability presentation. With GitHub code scanning you can view Snyk scan results in the Security tab on your GitHub repository, where vulnerabilities are organized and displayed clearly and interactively.

Before you proceed, you need to give GitHub Token for Actions read/write permissions at https://github.com/<your-github-username>/nginx-snyk-scaffolding/settings/actions. You can read more about GitHub Token permission in the official GitHub documentation.

Once you have given GitHub Token for Actions read/write permissions, update your CI to have the following configuration settings:

name: Snyk Container Scan
on:
  push:
    branches:
      - main
jobs:
  snyk:
    runs-on: ubuntu-24.04
    steps:
      - name: Check out repository
        uses: actions/checkout@v2
      - name: Build Docker image
        run: docker build -t <dockerhub-username>/custom-nginx .
      - name: Run Snyk to check for vulnerabilities
        continue-on-error: true
        uses: snyk/actions/docker@master
        with:
          image: <dockerhub-username>/custom-nginx
          args: --file=Dockerfile --severity-threshold=high
          json: true
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_AUTH_TOKEN }}
      - name: Convert Snyk JSON to SARIF
        uses: garethr/snyk-to-sarif@master
        with:
          input: snyk.json
          output: snyk.sarif
      - name: Upload scan results to GitHub Code Scanning
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: snyk.sarif

From the file above, after Snyk has checked for vulnerabilities, the scan results will be saved in a snyk.json file. Next, the “Convert Snyk JSON to SARIF” step will use the garethr/snyk-to-sarif@master action to convert it into a format that GitHub code scanning can parse (snyk.sarif). Once this process is complete, the sarif file snyk.sarif will be uploaded to GitHub code scanning.

Note, a SARIF file is a Static Analysis Results Interchange Format. A standard that lets analysis tools exchange results in a standard format.

Push your changes to trigger the workflow and head to the Security tab on your repository. You should see vulnerabilities with severity levels from high to critical.

Viewing Snyk scan results on GitHub code scanning

Scanning Custom Code and Open Source Libraries

Running security checks automatically for both your code and the libraries used in your projects is always good practice before deploying them to production or building and deploying them to a container registry. Again, you can do this with Snyk code and Snyk open source.

You’ll use Snyk code and Snyk open source to check for Vulnerabilities for a Django project that uses Poetry as the package manager. Run the command below to clone this project to your machine:

git clone git@github.com:mercybassey/django-snyk-scaffolding.git

Run the following command to install all dependencies:

poetry install

Create a .github/workflows/ci.yml file and paste in the following code:

name: Django Project CI/CD
on:
  push:
    branches:
      - main
jobs:
  snyk:
    runs-on: ubuntu-24.04
    steps:
      - name: Check out repository
        uses: actions/checkout@v2
      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.8'
      - name: Install Poetry
        run: |
          curl -sSL <https://install.python-poetry.org> | python3 -
      - name: Install dependencies
        run: |
          poetry install
      - name: Run Snyk Open Source Test
        continue-on-error: true
        uses: snyk/actions/python-3.8@master
        with:
          command: test
          args: --sarif-file-output=snyk-test.sarif
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_AUTH_TOKEN }}
      - name: Run Snyk Code Test
        continue-on-error: true
        uses: snyk/actions/python-3.8@master
        with:
          command: code test
          args: --sarif-file-output=snyk-code.sarif
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_AUTH_TOKEN }}
      - name: Upload Snyk Open Source Test Results to GitHub Code Scanning
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: snyk-test.sarif
      - name: Upload Snyk Code Test Results to GitHub Code Scanning
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: snyk-code.sarif

This workflow will set up Python “3.8” and use the Snyk Python action snyk/actions/python-3.8@master to scan your code and open source dependencies using the snyk code test and snyk test commands, respectively.

Create a new GitHub repository for this project, add the Snyk token as a secret, and give GitHub Token for Actions read/write permissions.

Commit and push your changes and wait for the CI to run to completion. Since the CI is configured to continue amidst Snyk vulnerability checks, you should have the following image indicating that the CI job ran to completion.

You’ll see a few vulnerability issues when you head to the Security tab on GitHub. This is Snyk doing its work, and if you look at the labels for each vulnerability issue, you’ll see the ones related to Snyk open source and Synk code:

Viewing Snyk open source on GitHub code scanning

If you scroll down, you will see just one related to the Snyk code, which is titled “HardCoded secret.”

Viewing Snyk code scan results on GitHub code scanning

Snyk open-source vulnerabilities can be fixed by upgrading dependencies to less vulnerable ones, and for Snyk code vulnerabilities, you’ll have to fix them yourself. To resolve Snyk open-source vulnerabilities, you have two options:

  • Use the snyk fix command to allow Snyk to automatically upgrade to its recommended open source libraries, or add a step in the CI that executes the snyk fix command for you automatically. However, this option is only available for Snyk enterprise users.
  • Manually upgrade to Snyk’s recommended open-source libraries on your machine.

To resolve the vulnerability related to the Snyk code, you have to remove the hard-coded secret.

Resolving open source libraries for Snyk open source

Activate the Poetry virtual shell and run a vulnerability check for Snyk open source with the following command:

poetry shell
snyk test

As I write this article, Snyk asks me to upgrade to Django 4.2.16 and sqlparse 0.5.0. Depending on when you see this article, the recommended versions might be different.

Issues to fix by upgrading dependencies:

Upgrade django@4.2.3 to django@4.2.16 to fix

✗ Regular Expression Denial of Service (ReDoS) [Medium Severity][<https://security.snyk.io/vuln/SNYK-PYTHON-DJANGO-5932095>] in django@4.2.3

introduced by django@4.2.3

✗ Denial of Service (DoS) [Medium Severity][<https://security.snyk.io/vuln/SNYK-PYTHON-DJANGO-6041515>] in django@4.2.3

introduced by django@4.2.3

✗ Regular Expression Denial of Service (ReDoS) [Medium Severity][<https://security.snyk.io/vuln/SNYK-PYTHON-DJANGO-6370660>] in django@4.2.3

introduced by django@4.2.3

....

Upgrade sqlparse@0.4.4 to sqlparse@0.5.0 to fix

✗ Uncontrolled Recursion [High Severity][<https://security.snyk.io/vuln/SNYK-PYTHON-SQLPARSE-6615674>] in sqlparse@0.4.4

introduced by sqlparse@0.4.4 and 1 other path(s)

Run the command below to install django 4.2.16 and sqlparse 0.5.0:

poetry add django@4.2.16
poetry add sqlparse@0.5.0

You should see the following output once this is successful:

Updating dependencies

Resolving dependencies... (0.4s)

Package operations: 0 installs, 2 updates, 0 removals

- Updating sqlparse (0.4.4 -> 0.5.0)

- Updating django (4.2.3 -> 4.2.16)

Writing lock file

When you run the snyk test command again, you’ll see the following, indicating all libraries are up-to-date and no vulnerabilities were found.

✔ Tested 7 dependencies for known issues, no vulnerable paths found

Resolving Hard Coded Secrets for Snyk code

Right now in my example, snyk code found a vulnerability at django_project/settings.py where a secret is being hardcoded. To resolve this, you’ll need to use environment variables.

First, in the root of the Django project, create a .env file and populate it. Do this by replacing <secret-key> with the actual key from django_project/settings.py.

DJANGO_SECRET_KEY='<secret-key>'

Next, edit the SECRET_KEY variable in django_project/settings.py to hold the value os.getenv("DJANGO_SECRET_KEY"):

This will load the value from the environment variable using os.getenv:

import os

SECRET_KEY = os.getenv("DJANGO_SECRET_KEY")

Then, create a .gitignore file in the project’s root and add the .env file to exclude it from version control:

# .gitignore
.env

Now, run snyk code test again to recheck the code. You should see the following results:

✔ Awesome! No issues were found.

And there you go, no more code security issues, at least those that have been identified so far!

Conclusion

In this article, you have learned what security scanning is, why you should implement security scanning in a CI/CD workflow, and how to use Snyk for vulnerability scanning in a GitHub actions workflow. You have used Snyk container to scan and identify vulnerabilities in an Nginx container image, used Snyk open source to scan open source libraries within a Django application, and used Snyk code to scan custom code. Snyk is a robust tool, you can integrate Snyk with Kubernetes, Jira, and Slack. See the official Snyk documentation to find more information about Snyk.

The post Using Snyk for CI/CD Security Scanning appeared first on Simple Talk.


Viewing all articles
Browse latest Browse all 5

Trending Articles