Chapter 2
6 min read

Exploring Container Security Tools

Snyk

Snyk is a container security tool, developed by Snyk Ltd. It can be used to analyze container images for known vulnerabilities. Snyk was integrated into Dock...

Snyk is a container security tool, developed by Snyk Ltd. It can be used to analyze container images for known vulnerabilities. Snyk was integrated into Docker CLI as a subcommand, docker scan, in 2020 until replaced by Docker Scout in 2023. Snyk is now available as a Docker Desktop extension and a standalone CLI tool. Unlike Trivy, Snyk is not open-source, but is free for public repositories.

My Snyk fun fact is that I've been a Snyk Ambassador since 2022. So, I have a hoodie from Snyk with my Twitter handle written on it. But now Elon Musk is destroying Twitter, and all my other social media accounts have different handles.

Installation

To use Snyk, one needs to create an account on Snyk.io and get an API token. The API token can be obtained from the account settings page. The token can be set as an environment variable, e.g. SNYK_TOKEN.

Snyk is available as a Docker Desktop extension, and can be installed from the Docker Desktop UI. I'll skip the UI stuff as I'm more of a CLI person. To use Snyk CLI, there are two ways:

  • Use the official Docker image,
  • Install the CLI binary.

Using the Official Docker Image

Using the official Snyk Docker image is a bit more verbose than using Trivy:

docker run --rm -it \
    --env SNYK_TOKEN=${SNYK_TOKEN} \
    -v /var/run/docker.sock:/var/run/docker.sock \
    snyk/snyk:docker snyk container test alpine:3.12

A few points:

  • There are multiple Docker images based on the things you want to scan. In this example, we use the snyk/snyk:docker image, which is used to scan Docker images. There is e.g. snyk/snyk:node for Node.js projects.
  • The SNYK_TOKEN environment variable is set to the API token obtained from Snyk.io.
  • The Docker socket is mounted to the container, so that the container can access the Docker daemon. This is needed because Snyk will pull the image to be scanned, and analyze it locally.

Since the command is quite verbose, you can define an alias to simplify it:

alias snyky='docker run --rm -it \
    --env SNYK_TOKEN=${SNYK_TOKEN} \
    -v /var/run/docker.sock:/var/run/docker.sock \
    snyk/snyk:docker snyk'

I called it snyky because it's a sneaky way to use Snyk and I don't want it to clash with snyk in case I install the CLI binary later.

snyky container test alpine:3.12

Installing the CLI Binary

There are multiple ways to install the Snyk CLI binary. The easiest way is to use NPM, if you happen to have Node.js installed on your system:

$ npm install -g snyk

If not, please confer the official installation instructions.

After the installation, you need to authenticate with Snyk using the API token:

$ snyk auth ${SNYK_TOKEN}

Analyzing Container Images

From now on, I'll use the command snyk, but you'll be able to do all the stuff with snyky as well.

To check a Docker image, say alpine:3.12, for known vulnerabilities, run the following command:

$ snyk container test alpine:3.12

The output of the command will be similar to the following:

Testing alpine:3.12...

✗ Critical severity vulnerability found in zlib/zlib
  Description: Out-of-bounds Write
  Info: https://security.snyk.io/vuln/SNYK-ALPINE312-ZLIB-2977082
  Introduced through: zlib/zlib@1.2.12-r0, apk-tools/apk-tools@2.10.8-r1
  From: zlib/zlib@1.2.12-r0
  From: apk-tools/apk-tools@2.10.8-r1 > zlib/zlib@1.2.12-r0
  Fixed in: 1.2.12-r2

Organization:      aerabi
Package manager:   apk
Project name:      docker-image|alpine
Docker image:      alpine:3.12
Platform:          linux/arm64
Licenses:          enabled

Tested 14 dependencies for known issues, found 1 issue.

Alpine 3.12.12 is no longer supported by the Alpine maintainers.

The output of the command shows that the image has one critical vulnerability, in the zlib library. There is also a link to Snyk's vulnerability database: SNYK-ALPINE312-ZLIB-2977082. Opening the link will show the details of the vulnerability, including the CVE, the reason for the vulnerability, and the affected versions.

Container Image Scan Output Formats

Snyk, like Trivy, supports JSON and SARIF output formats. The following is an example of the JSON output:

$ snyk container test alpine:3.12 --json

Like Trivy, the output here is huge, and has a list of vulnerabilities among other things. Here is the beginning of the JSON output:

{
  "vulnerabilities": [
    {
      "id": "SNYK-ALPINE312-ZLIB-2977082",
      "cpes": [],
      "title": "Out-of-bounds Write",
      "CVSSv3": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "credit": [
        ""
      ],
      "semver": {
        "vulnerable": [
          "<1.2.12-r2"
        ]
      },
      "exploit": "Not Defined",
      "patches": [],
      "insights": {
        "triageAdvice": null
      },
      "language": "linux",
      "severity": "critical",
      "cvssScore": 9.8,
      "malicious": false,
      "isDisputed": false,
      "references": [
        {
          "url": "https://github.com/ivd38/zlib_overflow",
          "title": "cve@mitre.org"
        },

The SARIF output is similar to the one of Trivy, and can be used to upload the results to the GitHub Security tab.

$ snyk container test alpine:3.12 --sarif

To store the SARIF file, you can use the following command:

$ snyk container test alpine:3.12 --sarif-file-output=sarif.json

This is essentially what we’ll replicate in the CI/CD pipeline.

GitHub Actions

Snyk can be used as a GitHub Action, and the results of the scan can be uploaded to the GitHub Security tab. The only difference here is that the token is set as a secret, so that the GitHub Actions workflow can access it.

The following is an example of a GitHub Actions workflow that uses Snyk to scan a Docker image:

name: "Scan Docker Application for Vulnerabilities"

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}-backend

defaults:
  run:
    working-directory: backend

jobs:
  docker_build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Log in to the Container registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: backend
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

  docker_scan_snyk:
    runs-on: ubuntu-latest
    needs:
      - docker_build
    steps:
      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

      - name: Run Snyk to check Docker image for vulnerabilities
        uses: snyk/actions/docker@master
        continue-on-error: true
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        with:
          image: ${{ steps.meta.outputs.tags }}
          sarif: true
          args: --file=backend/Dockerfile

      - name: Upload Snyk scan results to GitHub Security tab
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: snyk.sarif

In this example, we assume there is a Dockerfile in the backend directory. The Docker build part is similar to the example we covered with Trivy. The CI pipeline builds the Docker image and pushes it to the GitHub Container Registry. Then, it uses Snyk to scan the image for known vulnerabilities, and uploads the results to the GitHub Security tab.

Snyk GitHub Integration

Snyk also has a GitHub integration, which can be used to scan the repository for known vulnerabilities without the need for a CI pipeline. List of vulnerabilities then appears on Snyk's website and Snyk automatically creates pull requests to fix the vulnerabilities.

Exercises

  1. Create a GitHub Actions workflow that uses Snyk to scan a Docker image for known vulnerabilities, and uploads the results to the GitHub Security tab. Add it to your project of choice.
  2. Integrate Snyk with your GitHub repository, and scan it for known vulnerabilities.
  3. Create a SARIF report from Snyk and compare it with the one from Trivy.