Silicon Valley CISO Investments invests in Cyral·Read the press release
Blog

Security as Code: Implementing lint and gosec for Golang

Cyral subscribes to a security as code methodology to continuously maintain and monitor our security posture. If you are developing software in Golang, gosec is a great first step at implementing security as code in your CI/CD pipeline. In this blog we will talk about how to implement the static code analysis tool gosec from the Secure Go project. Gosec currently has a set of 31 rules that map to the Common Weakness Enumeration (CWE) framework. Those rules help to secure your code by covering 8 of the 2019 CWE Top 25 Most Dangerous Software Errors. You’ll need to take a multi step approach designed for your application to gain full coverage.

Static code analysis (SCA) also known as source code analysis or static program analysis, is a method of applying rules against source code in order to find software bugs. This is a great first step at automatically finding software bugs. Static analysis dates back to at least the early 1970’s and the PFORT Verifier for checking a FORTRAN program. The virtues of SCA even show up in a paper published in 1995, imploring its usage in industrial applications. Over the years a number of both commercial and free or open source static analysis tools have been created each with their own merits and limitations. For this post, we will cover gosec as it is incredibly fast and purely focuses on security rules. We will then show how easy it is to implement a lint solution for general bugs as well.

Implementing lint and gosec with GitHub Actions

Implementing gosec with GitHub Actions is incredibly simple. Simply create a new pull request with the sample action file already listed in the repo. To do so in a repo that has not been setup with GitHub actions before via CLI:

cd src/ #your top level source directory
git checkout -b feature/gosec-actions #create a new branch
mkdir -p .github/workflows
vi main.yml

In your main.yml file created above, copy and paste the following:

name: Run Gosec
on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
jobs:
  tests:
    runs-on: ubuntu-latest
    env:
      GO111MODULE: on
    steps:
      - name: Checkout Source
        uses: actions/checkout@v2
      - name: Run Gosec Security Scanner
        uses: securego/gosec@master
        with:
          args: ./…

Commit your code and open a pull request and you can then see the output in the Actions tab:

Implementing Security as Code: The output of running your code

You can now click into each of the portions of the tests and see the full logs.

Next week, a new version of gosec will be released allowing you to specify multiple arguments when implementing with GitHub Actions.

For example, you may be worried about breaking your existing builds and instead want it to run it without failing the build. To do so, you would use the following config:

name: Run Gosec
on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
jobs:
  tests:
    runs-on: ubuntu-latest
    env:
      GO111MODULE: on
    steps:
      - name: Checkout Source
        uses: actions/checkout@v2
      - name: Run Gosec Security Scanner
        uses: securego/gosec@master
        with:
          args: -no-fail ./…

Once your tests run, you can now view them in GitHub and decide what action you would like to take. If you manually review the code and find a false positive, there are multiple different ways to annotate the code with the tag #nosec to ignore on future runs. For example:

import "md5" #nosec

The gosec documentation has further ways to annotate blocks and even modify configuration of specific rules to fit your project.

To enable linting of your project you can use the authors of golangci-lint official GitHub action.

Implementing lint and gosec with GCP Cloud Build

Since you’re working with Golang, you may instead be running Cloud Build on GCP. If you are, you can use the following config in your cloudbuild.yaml and cloudbuild.release.yaml files:

# Run security tests
- name: securego/gosec
  env:
  - 'GO111MODULE=on'
  args:
  - -no-fail #don't fail the build
  - ./...
  volumes:
  - name: 'go-modules'
    path: /go
  id: 'security-tests'
  waitFor: ['unit-tests'] #wait for another step to finish

# Run lint
- name: golangci/golangci-lint
  env:
  - 'GO111MODULE=on'
  args:
    - golangci-lint
    - run
    - --issues-exit-code=0 #don't fail the build
  volumes:
  - name: 'go-modules'
    path: /go
  id: 'run lint'
  waitFor: ['unit-tests']

Once they run, you can then click through your build steps to see what failed:

Implementing Security as Code: A screenshot of your build steps

Next Steps: Implementing Security as Code

gosec and golangci-lint are great ways to begin with security as code for your Golang projects. We’ve taken you through 2 different build systems, but there are multiple ways to add them to your CI/CD pipeline or even run them locally. If you’re looking to continue your security as code journey with gosec, I would suggest editing your configuration to output a file that you can then import into another system to be able to follow up with the results. One of the projects that we mentioned in The Security Digest this week was DefectDojo. DefectDojo can import gosec results in JSON format and has a ton of other plugins as well.

#TogetherWeDefendBetter

Stay Connected