In response to a rapid increase in software supply chain attacks, Security Professionals and Software Development Leaders are increasingly motivated to improve their overall SDLC (Software Development Lifecycle) security. But how do you begin? These guidelines can help you take the first step in defending yourself against supply chain security threats and avoid being the victim of the next highly publicized “SolarWinds”-class of supply chain attack.
Step 1: Mapping the Attack Surface
Software supply chain security risk can span multiple systems and services, unlike other attack vectors focused on networks or endpoints for example. One of the first steps in securing your environment should be mapping out your SDLC pipeline to better understand the surface area that needs to be protected. Every step of this pipeline can be affected by supply chain risk, so this is an important first step.
The SDLC pipeline is the sum of all the systems used to deliver a software application from code to deployment and can be made of various servers, cloud services, and other software solutions.
Most commonly, the SDLC pipeline is made of four primary categories -
- SCM (Source Code Management) systems (for example: GitHub)
- Build or CI/CD systems (for example: Jenkins)
- Artifact repositories (for example: JFrog Artifactory)
- Production systems
SCM systems are the systems used to store, develop and review the software source code. Examples of SCM systems include GitHub, GitLab, Bitbucket and more.
Nowadays, many SCM systems come bundled with other components like a build server, or an artifact repository. For the sake of simplicity, we will refer to these as distinct services, even though they are often bundled together in the same product.
Build or CI/CD systems are used to test, build and deploy the software. They define the build pipeline. Some examples of build systems are Jenkins, GitLab CI, CircleCI and more.
Artifact repositories are systems used to store and retrieve software artifacts. A common practice is to build an artifact, for instance, a container, store it in an artifact repository, and later, pull it for deployment. The artifact, therefore, is accessed by the build servers, or directly by the production systems. Examples of artifact repositories include JFrog Artifactory, Sonatype Nexus, AWS ECR and more.
Finally, production systems are the environments used to host the application code. These can be cloud-based environments leveraging Kubernetes or other containerization frameworks, on-premises bare metal servers, or any other solution used for executing a live application.
Discovering and keeping track of your SDLC assets traditionally has been a challenge, as it requires intimate knowledge of all the development processes and tools within your organization. Your development organization may comprise many teams, each utilizing a different tech stack and having other development processes.
This process can be automated using a data-flow approach. Consider code stored in an SCM system that needs to be sent to a build server to be built as an artifact. The build server needs to be aware of changes in the source code to trigger a rebuild of the artifact. This may be accomplished using a Webhook, for example. Various mechanisms facilitate these updates throughout the SDLC pipeline, and these mechanisms can be traced from one system to the other to provide a data-driven overview of the development pipeline.
Step 2: Defining Policies for Secure Development
After mapping out your SDLC assets, you’ll need to define and enforce your secure development policies to mitigate risks moving forward.
At its core, software supply chain security risk occurs through openings and leaks in your SDLC pipeline that allows a person or an unverified third party to tamper with your application before its deployment in the production environment. These security policies aim to minimize these openings and leaks as much as possible.
Without prior experience in this security field, this task can seem overwhelming. I do highly recommend engaging with a security expert or cybersecurity vendor with subject matter expertise in this area, but there are three common techniques where you can get started on your own:
- Least privilege – Every user or system should be granted the minimum level of permissions it needs to perform normally. This reduces the risk of stolen credentials being used to compromise SDLC systems.
- Review – Every change in the system or the code should be reviewed by another authorized person to ensure the change is justified and safe. This is extremely important with the increasing use of GitOps and Config-as-Code practices. Code changes are not just changes to application logic; they can also change the pipeline configuration, permission models and security policies.
- Authentication – Every actor in the system should prove their identity in the most comprehensive way that is feasible, such as MFA (Multi-Factor Authentication).
Your security policies should strike a balance and be pragmatic. They should be as strict as possible, but still satisfy other business needs and requirements including developer agility. A small startup might be OK with defining a closed list of allowed contributors to a code base, but a public OSS project will have to settle for a list of authorized reviewers. Similarly, an end user in an organization today can be obligated to use MFA without much difficulty, while requiring all automated scripts to identify using MFA may prove more complex.
At the end of this step, you should have defined security policies systems in your SDLC pipeline. Before enforcing these policies, they should also be shared with stakeholders and contributors in your organization to promote awareness and further improve them through collaboration.
Step 3: Enforcing your Security Policies
The final step is policy enforcement. Every SDLC system is different, and while some systems have built-in controls and configurations to enforce these policies, others will require manual or custom solutions.
It is worth taking the time to explore the various configurations and security features of each SDLC system, as it is often the case that a specific security policy can be enforced using a combination of configuration options that you might not have encountered before.
As a simple example, most git based SCM systems today allow configuring a list of approved reviewers for code changes in a software project using pull requests, allowing you to enforce the basic review policy in your project.
In addition, if an SDLC system allows enforcing your security policy using configuration options, also consider periodically checking them for configuration drift (manually or programmatically). Systems may be reconfigured by uninformed individuals, or as part of a software version upgrade, and as such their configuration should be tracked to make sure it does not violate your security policy over time.
Enforcing your security policy is often the most time-consuming step in protecting your SDLC pipeline. Across different systems, different concepts are commonly renamed and reclassified slightly, requiring you to spend time in each system separately in order to secure them in the most optimal manner. Prepare to put the most effort into this step.
Step 4: Don’t be a pipe
Enforcing optimal software development policies can go a long way to creating guardrails against an attacker exploiting your environment to introduce a malicious change in your application. However, I want to cover one additional aspect of security, and that’s supply chain risk introduced by other software dependencies, third-party services with access to your code, and vendors whose software you rely on.
For example, a malicious payload or hand-crafted vulnerability in an upstream library can affect your code base, and allow your consumers to be compromised, with you acting as the pipe. While this risk cannot be eliminated completely, software projects today are expected to employ tooling to minimize the risk of being a middleman in a supply chain attack originating at an upstream vendor or library.
One of the most effective ways to defend yourself today is the usage of dependency scanning techniques. In these techniques, a dependency manifest file is scanned to find dependencies which are known to be compromised, and a code change can be triggered automatically, or a notification can be sent to a designated contact.
Dependency manifest files are utilized for many common packaging systems such as NPM, Maven, NuGet, and more.
You can scan these dependency manifests using a variety of custom solutions, comparing them against any of the publicly available advisory databases, or use third-party tooling and services such as the ones offered by Snyk, Checkmarx, WhiteSource and others.
We’re here to help
After reading this post, I hope you have a better understanding of how to secure your development operation from supply chain risk. This was just an introduction to the topic, and there are new emerging frameworks to dive deeper into ways to protect these environments. One of the most promising ones is the SLSA framework, which we wrote about in a separate article explaining SLSA. If you’d like to learn more about other attack patterns distilled from popular frameworks check out The 3 Riskiest Software Supply Chain Attack Patterns Across Frameworks.
The principles of securing your SDLC pipeline may appear simple and straightforward, but in practice it gets complicated and time-consuming quickly, especially as your organization scales. Legit Security aims to make the process of securing your SDLC much easier, and we’ve developed a SaaS-based platform to do that. Contact us if we can help or you’d like to learn more.