DEV Community

loading...
Cover image for SnykCon - Making Sense of Container Security with Snyk CLI and GitHub Actions

SnykCon - Making Sense of Container Security with Snyk CLI and GitHub Actions

mcastellin profile image Manuel Castellin ・7 min read

I'm so excited I've participated in SnykCon 2020! 🔥
Listening to the talks lit a fire in me, and I really want to take container security seriously from now on, knowing how much easier it is today with tools like Snyk 🚀

But after running a container scan...

... on a couple of very simple projects, well, this is not the result I was expecting: 🤯🤯🤯
Overwhelming amount of issues

This was literally an "Hello World!" type of project, what is going to happen if I scan a real project? How do I start making sense of this?

Let me do a quick introduction and then I'll show you how I practically approached this problem 😉

A modern approach to security - DevSecOps

As I learned from this year's conference, finding vulnerabilities early on in the software development cycle is paramount in this day and age.

With the adoption of Continuous Delivery, hence shorter release cycles, we can no longer afford to wait for a team of security experts to validate every release. New code will already be running in production by the time they complete their audit!

Also, developers are the best people that can contextualize the vulnerabilities, and take action to fix them. 👨🏻‍💻

Shifting the responsibility towards developers

Ok, this is a nice concept, developers are now responsible for security too! But hold on a sec, they're developers! How can we expect them to do their job, and also monitor their software for vulnerabilities every day?

This is where I think people at Snyk have done a great job. Their tools are focused on helping developers with:

  • identifying vulnerabilities as early as in the developer's laptop
  • providing command-line tools that can be integrated into CI/CD workflows
  • monitoring generated artifacts to proactively notify the team when new vulnerabilities are discovered
  • advise on actions to fix vulnerabilities directly in the CLI for developers to see

My experience with Snyk Container scan

Given that there's no such thing as absolute security, this is the process I followed to get as close as I could for my demo container.

If you want to have a look at the repository, you can find it here. It's a simple "Hello, World!" Python project, that, when I started, had a whopping 267 vulnerabilities!

Step 0 - creating a Snyk account

The first thing to do is to create a Snyk account. This is required to start using the CLI tools from your development machine. See below, you just need to authorize the app with one of your existing accounts
Create Snyk account

After creating the account, Snyk will generate your personal API token. This is needed to use the CLI tools from command-line and from your CI/CD workflow.

If you already have an account, you'll find the token under Your Name > General Settings > API Token
API token settings

Install the CLI tools with npm and authenticate with your token:

# Install Snyk CLI with npm
> npm install -g snyk

# Authenticate with your Snyk account
> snyk auth ${YOUR_API_TOKEN}
Enter fullscreen mode Exit fullscreen mode

We're now ready to scan our project! 🚀

Step 1 - start from the development machine

As I learned in the conference, the best way is to start in your development machine using Snyk CLI.

First I wanted to make sure my python dependencies are clean from vulnerabilities. I'll do that directly from the command-line by running

> snyk test
Enter fullscreen mode Exit fullscreen mode

snyk test command

And it immediately found an issue with my requirements.txt file.

What's cool about this, is that Snyk tells me that the vulnerability in sqlalchemy@1.3.17 has been resolved in a later version of the package, so I will just upgrade it to the suggested version sqlalchemy@1.3.19.

Container image scanning

Next, I want to run a container scan to make sure my image has as little vulnerabilities as possible.

To do that, I first need to build the image, and then I can immediately scan it from the command line with snyk container test:

> snyk container test --file=Dockerfile snyk-container-demo
Enter fullscreen mode Exit fullscreen mode

By using the --file=Dockerfile we can tell Snyk which Dockerfile generated the snyk-container-demo image. This way we'll be able to get more accurate suggestions from the advisor.

And then I started to cry 😭
total issues first report

Stay calm and keep reading

This is what I told myself when I first read this report. Despite having soo many issues reported (267 to be exact), the report is also suggesting alternative images to the one I am currently using for the project:

Recommendations for base image upgrade:

Alternative image types
Base Image                  Vulnerabilities  Severity
python:3.9.0rc1-slim        73               17 high, 12 medium, 44 low
python:3.9.0b5-slim-buster  73               17 high, 12 medium, 44 low
Enter fullscreen mode Exit fullscreen mode

This is pretty nice! I can see that the -slim and -slim-buster versions of my base image have fewer vulnerabilities. So next thing I'll do is changing my Dockerfile to use one of those.

And after applying the suggestion...

... I was glad to see that the number of vulnerabilities found was drastically reduced!
reduced vulnerabilities second scan

In this report, Snyk is also telling me that I'm currently running on the most secure version of the selected base image, remember, there's no such thing as absolute security 😅

Being happy with the base image I selected, I can commit the changes in the repo and move on with the process.

Step 2 - CI Integration

I will now integrate Snyk with my Continuous Integration workflow. I don't have any in this project yet, so I'm going to use GitHub Actions.

With a quick Google search, I found out that Snyk already published a GitHub action I can use to scan my repository on every commit and collect the results in the Security tab of the GitHub repo.
snyk docker action

I will then copy the template provided, and create a new file in my repo in the .github/workflows directory called secscan.yml:

name: Container Scan
on: push
jobs:
  snyk:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Build the Docker image
      run: docker build -t mcastellin/snyk-container-demo .
    - name: Run Snyk to check Docker image for vulnerabilities
      # Snyk can be used to break the build when it detects vulnerabilities.
      # In this case we want to upload the issues to GitHub Code Scanning
      continue-on-error: true
      uses: snyk/actions/docker@master
      env:
        # In order to use the Snyk Action you will need to have a Snyk API token.
        # More details in https://github.com/snyk/actions#getting-your-snyk-token
        # or you can signup for free at https://snyk.io/login
        SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
      with:
        image: mcastellin/snyk-container-demo
        args: --file=Dockerfile --exclude-base-image-vulns
    - name: Upload result to GitHub Code Scanning
      uses: github/codeql-action/upload-sarif@v1
      with:
        sarif_file: snyk.sarif
Enter fullscreen mode Exit fullscreen mode

I have pretty much used the standard values here, except for the args: --file=Dockerfile --exclude-base-image-vulns.

By adding the --exclude-base-image-vulns parameter we are telling Snyk not to report vulnerabilities that are introduced by Docker base image layers. This is to make sure that we are breaking the build only when we introduce new issues in the Dockerfile.

The reason for ignoring base image vulnerabilities is to avoid having too much noise in the CI scan. We have already accepted the base image so we're only interested in blocking the issues we add with our customizations.

Before committing our GitHub Action YAML file, we have to configure the secret.SNYK_TOKEN in our registry. In the GitHub repository settings, go to Settings > Secrets > New Secret and configure the value for the Snyk token:
add new secret to github

We can now push our changes and see the result of the security scan:
github action scan results

Step 3 - Breaking the build

After all the effort fixing vulnerabilities I really want to make sure nobody can introduce new ones! Let's modify our Dockerfile and open a Pull Request that introduces an insecure package: curl, who knew!? 🤔

...

RUN apt-get update \
    && apt-get install -qqy curl \
    && rm -rf /var/lib/apt/lists

...
Enter fullscreen mode Exit fullscreen mode

Found it!

build broken

And the container scan found new vulnerabilities, giving us the peace of mind, that if anyone installs dodgy packages we'll be able to catch it before merging the code into the main branch!

Step 4 - Analyzing the report

detailed vulnerability report

For every issue found by Snyk you'll get a very detailed report, telling you:

  • what file introduced the issue
  • a description of the vulnerability
  • remediation advice

remediation advice

Wrapping up

It's been a fun couple of days for me to attend to SnykCon 2020 and I hope by sharing my first experience with Snyk and container scanning, I have also encouraged you to learn how to make the most out of these tools to keep your applications secure!

Thanks for reading! And don't forget to follow me if you want to see more content like this!

Discussion

pic
Editor guide