rss linkedin linkedin gitlab github twitter mastodon instagram
Software Architecture in Go: Security - Dependencies
Oct 08, 2021

Disclaimer: This post includes Amazon affiliate links. If you click on one of them and you make a purchase I’ll earn a commission. Please notice your final price is not affected at all by using those links.

Welcome to another post part of the series covering Quality Attributes / Non-Functional Requirements, this time I’m talking about Security specifically when dealing with Dependencies.



Security is important

Security is very important and also a huge and complex topic, I’m stating the obvious for sure but I want to make it clear that this post is focused on Securing Dependencies. What this is means in practice is having a way to determine if the packages we use are not exposed to known vulnerabilities, this includes the standard library packages as well as third party packages.

I will share with you a few different tools to determine if the packages we use are secure and up to date. To make all of this to work we need to have something in place already: Continuous Integration. If you don’t have this I recommend you to invest some resources to have it, because by using Continuous Integration a lot of the things I’m going to be sharing would be automated and easier to implement.

Securing Dependencies

Whether you use Github Actions, CircleCI, JenkinsCI or GitlabCi; the steps I’m going to show you are going to be similar, the key component is to have a way to automatically determine if the packages we use are:

  1. Up to date, and
  2. Vulnerability free

The tools I recommend adding to your Continuous Integration to determine if those requirements are satisfied are the following:

  • Dependabot,
  • gosec linter,
  • Snyk service,
  • CodeQL, and
  • versions.

Dependabot

Dependabot is a service part of Github that allows us to keep our dependencies up to date, it supports multiple programming languages, it’s Open Source and in some cases there are alternatives compatible to concrete CI-services, like GitlabCI.

The way Dependabot works is by defining a configuration file associated to your repository that indicates the Package Ecosystem, like Go Modules, NPM, Maven or Docker (to mention a few); as well as a concrete interval to use for checking if there are updates available to the packages being used.

Because Dependabot is part of Github, it integrates nicely with Github Actions, a simple configuration to enable checking for Go modules for my To-Do Microservice Example looks like:

 1version: 2
 2updates:
 3  - package-ecosystem: "gomod"
 4    directory: "/"
 5    schedule:
 6      interval: "daily"
 7  - package-ecosystem: "gomod"
 8    directory: "/internal/tools/"
 9    schedule:
10      interval: "daily"

This would create Pull Requests when new versions are available, for example:

Dependabot Pull Requests

Please refer to the official Dependabot documentation because there are more things included in dependabot like ignoring certain versions for example.

gosec linter

gosec is a Go linter that comes bundled as part of golangci-lint, but it also works stand alone if you prefer it that way. This linter includes multiple rules to detect, among other things:

  • Harcoded credentials,
  • SQL query construction using strings, that could lead to SQL injection, and
  • Detect usage of some crypto packages in the standard library.

When using golangci-lint make sure you have this linter enabled, to do that update your .golangci.yml and make sure it’s part of the list of enabled linters, for example:

linters:
  enable:
  - gosec

Snyk

Snyk is a paid service that detects vulnerabilities found in our projects, it not only detects issues in the packages used to build our artifacts but also other dependencies like Dockerfiles. I linked some of my Open Source projects on Github and to date they look like this:

Snyk Main Page

If we look at nit, you can notice that it’s also doing some Code Analysis and, like I mentioned before, it’s also checking Dockerfiles.

Snyk nit Page

Snyk also includes a list vulnerabilities Database, for example for Go, it looks (to date) like this:

Snyk nit Page

Finally depending on our configuration we may want to also enable creating Pull Requests automatically when new issues are detected, for example Snyk created this one for upgrading Alpine in the Dockerfile.

CodeQL

CodeQL is a service to discover vulnerabilities across a codebase using their semantic code analysis engine. Similar to Dependabot, enabling it on Github is simple, we only need to add a new workflow:

 1name: "CodeQL"
 2
 3on:
 4  push:
 5    branches: [main]
 6  pull_request:
 7    branches: [main]
 8  schedule:
 9    - cron: '19 4 * * 1'
10
11jobs:
12  analyze:
13    name: Analyze
14    runs-on: ubuntu-latest
15    permissions:
16      actions: read
17      contents: read
18      security-events: write
19    strategy:
20      fail-fast: false
21      matrix:
22        language: [ 'go' ]
23    steps:
24    - name: Checkout repository
25      uses: actions/checkout@v2
26    - name: Initialize CodeQL
27      uses: github/codeql-action/init@v1
28      with:
29        languages: ${{ matrix.language }}
30    - name: Autobuild
31      uses: github/codeql-action/autobuild@v1
32    - name: Perform CodeQL Analysis
33      uses: github/codeql-action/analyze@v1

Which to be fair, was practically autogenerated after enabling it on the project, to do so:

  1. Go to your project Settings,
  2. Click Security & analisys, and
  3. Click Set up for Code Scanning

From there you can add the CodeQL Analysis workflow that will let you to push the configuration file directly to your repository.

versions tool

versions is a tool I wrote to determine the package versions used by multiple projects, at the time I didn’t know about Dependabot so doing something like opening Pull Requests automatically to upgrade versions was something planned but in the end I decided to focus more on building some-sort of reports other tools could import.

To date versions is used to create a list of the packages each project uses, their versions as well as the Go version they use, however it only works for projects using Go modules. One thing I do like about versions is the fact that Go versions are listed as well, this is important because of Go’s Release policy, where only the last two major versions are supported, having a tool like this let us know when it’s time to upgrade to a newer major version.

Conclusion

Security is usually an after-thought when building services but it shouldn’t be that way, we already have tools and services that allows us to detect issues automatically, however those require in most cases to have Continuous Integration in place, so this is another great reason to add that to your development pipeline.

This is not an extensive list for sure, I will continue covering more Security related topics for Go in future posts, stay tuned.

If you’re looking to sink your teeth into more Software Architecture I recommend the following links:


Back to posts