What does a good DevSecOps pipeline should look like from a code security perspective? We hear this question often, and even though there are multiple answers, we’ve put together a blueprint that everybody could easily start with.
Introducing the DevSecOps funnel
The goal of DevSecOps, or modern code security practice if you prefer, is to embed security controls as early as possible in the development process, in order to remediate as many defects as possible, as soon as possible, with minimum friction.
Let’s start by clarifying a first myth, developers, even augmented with great developer-first security solutions like Bearer, will never be able to tackle every security defect by themselves. Application security teams are crucial and will always be, but their time and effort should be focused on what matters the most. Triaging hundreds of defects is not part of it!
Now that we’ve clarified the objective of a modern code security practice, Pareto’s law is a good way to think about the outcome, essentially remediating 80% of the security defects before the security team need to be involved.
In reality, we should not talk about a DevSecOps pipeline, but a DevSecOps funnel, where security defects diminish at every step.
Step 1: Code review checks, aka CI integration.
CI checks are conducted when a developer's code is nearing completion, the feature is preparing to be merged into the main branch of the application, and subsequently distributed to all developers before being released in production.
Typically, a CI system performs various checks, including code tests, to ensure that feature regressions are not introduced. Additionally, at this stage, developers are frequently required to seek code reviews from their peers in order to obtain a green approval. In many cases, a few comments may be provided, necessitating minor adjustments by the developers.
Without much surprise, this is also the best place to perform security checks in a DevSecOps funnel.
For a good CI integration of a code security scanning tool, you need to make sure that:
- It’s fast, a CI can quickly become slow and no one likes to wait, especially in a fast paced development environment where multiple features get merged every day. Also, CIs are not cheap, the slower they run, the more expensive the bills are at the end of the month.
- It runs only on code diff, meaning only the code that developers added/modified as part of the CI check is getting scanned. Otherwise, you will find defects that “don’t belong to them”, creating massive friction. Also, the scan will be much slower.
- It has a good level of accuracy. There is nothing more frustrating than a false positive, especially for a developer that is not heavily trained to distinguish them.
- It talks the developers' language. Again, developers are not security experts, if the solutions find a defect, it’s important to make sure it provides information in a developer friendly manner, so they can quickly fix it.
As mentioned at the beginning, the goal is not to remediate 100% of the defects. Some security defects can only be found when the whole code is assembled, so checking only files changed as part of the CI won’t be enough. Also, some security checks can be very tricky, and therefore subject to a high number of false positives. In that case, it’s advised to disable them in the CI to not frustrate developers. This brings us to our next step, the CD.
When using Bearer CLI, our Open Source SAST scanner, you can easily integrate it into your CI pipeline, using our GitHub code review comments integration, or GitLab merge request comment integration.
Step 2: Predeployment checks, aka CD integration.
Once code is merged into the main branch, it gets deployed quickly after, often as part of multiple changes. In the CD, there are again a certain number of checks usually performed, tests once again for example, which make it another good opportunity to add security ones.. Though, contrary to the CI, CD checks are not supposed to fail often, or if they do, it’s for a major reason. Indeed, the whole user experience of a CD is not meant to manage failures often. For that reason, it’s advised to only fail the CD on high or critical defects - depending on your risk appetite.
In addition, since at this step a bunch of new code is merged together to be deployed, usually developers are not waiting for the CD to complete. This allows CD checks to potentially take longer than in a CI, which creates altogether the opportunity to run a full code security scan.
Overall, a good solution will require:
- Great finding prioritization capabilities to make sure CD fails only on the most important defects.
- A certain level of control over when and how to fail, based on criticality and/or certain types of rules.
- Good quality of the output, considering it will probably not be the developer directly responsible for the failing code that will get the results first, but an SRE or DevOps.
- And still fast scanning capabilities considering the entire codebase will be scanned contrary to the CI.
By now, 80% of the security defects will have been tackled by now, meaning that a lot of your production code is clean, especially the critical defects. So what happens to the remaining 20%?
When using Bearer CLI, you can easily integrate it into your CD pipeline, using our pre-build GitHub Action or GitLab CI configuration. Thanks to our sensitive data dynamic prioritization and highly flexible CLI commands, your integration should be very effective.
Step 3: Regular checks, aka scheduled scans.
This might sound counterintuitive as part of a modern DevSecOps funnel, but doing a regular scheduled scan is still very important. As we said earlier, even in the best DevSecOps environment, there will always be a certain number of defects unresolved once code has been deployed in production.
There are many good reasons for such:
- New defects arise on old code, either because the checks your solution is performing are evolving or simply because researchers discovered new vulnerability patterns.
- Some checks are disabled in CI/CD for performance or accuracy reasons.
- Findings will have been by-passed at some point, most probably with consent, usually for business timing constraint, but will still need to be resolved at some point.
In addition to those practical reasons, compliance is another important one. To be able to track, control and demonstrate your security posture, showing full scan results across your codebase on a regular basis is often needed.
A good solution will provide the ability to:
- Schedule scans easily and often, and tweak settings on a per-repo basis.
- Allow to get notified of new defects and easily filter them with a risk impact analysis.
- Provide a remediation workflow to quickly transform defects into tickets directly assigned to the right developer.
- Track KPIs and demonstrate the evolution of your security posture over time.
If you are already using Bearer CLI, you can easily integrate scan results into Bearer Cloud and start to manage your product and application code security program at scale.
But what about security checks while writing code?
Indeed, writing and committing code to an SCM is the first step of a development pipeline, so why isn’t it the first step of the DevSecOps funnel?
Most developers already perform some sort of code checks while writing code, usually code style ones, thanks to linters. Adding security checks too sounds like a good idea, and there are two ways to do so; as a code editor plugin, or as a git pre-commit hook.
Both are great solutions, but they come with some caveats:
- Productivity challenges. If you’ve written code before, you know that it often gets rewritten a few times before being shipped, and sometimes even gets completely scrapped. Performing security checks too early can lead to a useless workload addition for developers, especially when developers are asked to focus on the creation aspect. The same debate exists when writing code tests.
- Enforcement challenge. From a security organization point of view, it’s difficult to enforce any of those solutions since local developer’s environments are rarely fully controlled or managed, since they tend to want to bring their own tools.
- Implementation challenge. Code editor plugin our pre-commit hook need to be very fast, almost invisible. Developers write and commit code many times a day and won’t tolerate any slowdown here.
At Bearer, we believe that shifting further left is a great addition to the DevSecOps funnel, but because of the caveats mentioned above it needs to be very carefully considered and can’t be considered as a must-have yet.
As we’ve seen, the DevSecOps funnel follows part of the DevOps pipeline, but with different objectives, methods and constraints.
Below you can find a DevSecOps funnel that we recommend you should use to start a modern code security program.