As a developer, I’ve built apps and wrote code. As a cheesecake connoisseur, I’ve tried many different kinds of cheesecake. After I got to talk to some of the bakers, I realized that building apps and baking cheesecake have a lot in common. It all starts with knowing and trusting your ingredients.
According to Tidelift, over 90 percent of applications contain some open source packages. Developers choose open source because they believe it’s better, more flexible, and more extendible. A lot of developers also fear how well packages are maintained and how security vulnerabilities are identified and solved.
Whether you deploy your apps as functions, containers, or on virtual machines, trusting your ingredients will always be an essential part of building secure code. In the first nine months of last year, close to 17,000 new vulnerabilities were discovered. Almost two-thirds of the disclosed vulnerabilities can be solved by upgrading or patching.
IBM Security, with its Cost of a Data Breach report, looks at the costs for companies when something does go wrong. On average, it takes companies 279 days to identify they have a security breach and contain it. The average cost of a security breach is $3.92M and the US stands out with an average of $8.19M.
The sooner you realize that the packages you’re using have a security flaw, the easier it is to fix it. That saying remains true whether you deploy your apps as containers, on virtual machines, or as functions. From a security point-of-view, you’ll want to:
- Get your dependencies from a trusted source;
- Scan your dependencies for known vulnerabilities;
- Keep track of which dependencies you have deployed.
Let’s look at these three pieces in a little more detail when you’re dealing with functions.
Trust, but verify
No matter which programming language, you want to make sure that your dependencies come from a trusted location. These locations can be internal, like JFrog Artifactory or Sonatype Nexus, or external. For example, Python developers will get their modules from PyPi and Node.js developers will get their modules from NPM. Quite recently, the Go community got its module mirror and checksum database too. All of these sources give developers the ability to verify the integrity of the package they’ve downloaded.
If you’re a Go developer, like me, using Go modules with the checksum database will help when you want to verify the integrity of modules. For example, if my go.sum
file (which gets checksums from the database) contains a different checksum than go get
calculates it’ll stop you from downloading the module.
$ go get ./...
verifying github.com/aws/aws-sdk-go@v1.27.0/go.mod: checksum mismatch
downloaded: h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
go.sum: h1:HmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
SECURITY ERROR
This download does NOT match an earlier download recorded in go.sum.
The bits may have been replaced on the origin server, or an attacker may
have intercepted the download attempt.
As a developer, regardless where I deploy, this helps me make sure my ingredients come from a trusted location and are not tampered with.
Finding known vulnerabilities
Getting your dependencies from a trusted location solves one part of the problem. The second part of the problem is finding vulnerabilities in those dependencies. There are lots of solutions available depending on your language of choice. Using the UI, GoCenter shows if the module you’re looking at has any vulnerabilities (in any of the versions indexed by GoCenter). The red warning sign in the image below shows how that might look.
The team at Snyk.io, allows developers to sign up for a free plan and use the Snyk CLI for unlimited tests on open source projects and 200 tests on private projects. The Snyk CLI gives developers, for a lot of different languages, the ability to find and fix vulnerabilities in the dependencies of a project. Simply running snyk test
will list all the vulnerabilities, including suggested fixes if there are any.
Testing /github/workspace...
Organization: retgits
Package manager: gomodules
Target file: go.mod
Project name: github.com/retgits/testrepo
Open source: no
Project path: /github/workspace
Licenses: enabled
✓ Tested 200 dependencies for known issues, no vulnerable paths found.
Next steps:
- Run `snyk monitor` to be notified about new related vulnerabilities.
- Run `snyk test` as part of your CI/test.
Keeping track of dependencies
Manually validating that your dependencies are safe is a good practice for developers. Automating that, however, is even better. If you decide to give Snyk access to your source code repositories, you’ll get the ability to have Snyk automatically test all pull requests, automatically create pull requests to fix any security vulnerabilities it finds, and even raise pull requests to update out-of-date dependencies. This is all on top of periodically scanning your dependencies for new vulnerabilities.
Making sure that every build or deployment of your function is also checked helps keep your data safe. In my CI/CD pipelines, I run a vulnerability scan on every push. The yaml snippet below is all that’s needed to let Snyk scan your dependencies every time your GitHub Actions pipeline runs.
- name: Vulnerability scan
id: synk-test
uses: snyk/actions/golang@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
If your functions are built using Node.js, Ruby, or Java you can even connect Snyk directly to your AWS Lambda functions to monitor the deployed dependencies for vulnerabilities. This makes sure that if there are any new security vulnerabilities with the actual deployed and running code, you’ll know just as quick as Snyk does.
What’s next
With more and more apps contain open source packages, we’re collectively responsible to make sure we get dependencies from a trusted source, we scan our dependencies for known vulnerabilities, and keep track of which dependencies we have deployed. Keeping our apps and our data safe is a shared responsibility. As we’re all working on better security, let me know your thoughts and send me or the team a note on Twitter.