Software development has changed dramatically in recent years, as technologies like DevOps, application containers, and cloud-native transform how software is built and distributed. Unfortunately, attackers have been paying close attention to these changes, and have retooled their attack strategies to take advantage of relatively weak security controls in software development and build environments. Attackers recognize that security teams are more focused on protecting infrastructure and less focused on software development and supply chains. This is how damaging attacks like SolarWinds happen – and it’s likely that attackers will strike again to yield even more successful outcomes.
A new approach is needed to secure the software development pipeline. What’s more, this approach needs to be put in place by the engineers developing the software—and not by information security teams. Engineering teams need to be responsible for design and implementation while giving security teams visibility and assurance that controls are operational and that policies are being enforced.
A new blueprint for securing the pipeline centers on a flexible set of controls that secure the software build pipeline by ensuring that authentication and authorization are properly managed, that the integrity of software artifacts are tested at appropriate stages and that controls are placed on third-party and open source solutions incorporated into the software. The result: Software innovation and delivery at lower risk of supply chain tampering, and reduction of attacks during development.
A Pragmatic Design Philosophy
This modern software security blueprint is based on the following design philosophy:
- Least-privilege: Only grant the access and permissions required to accomplish a job, and no more.
- Immutability: Artifacts and infrastructure are not modified after deployment to an environment. If a change is required, it’s done in the image or script in the development environment and then promoted through the higher environments.
- Everything-as-code: Infrastructure, security policies and other parts of the pipeline are also implemented as code and subject to the same controls as the software artifacts.
- Traceability: All changes, whether to infrastructure or business code, are version-controlled.
Controls Blueprint for Software Development Pipelines
The basis for this software security blueprint centers around a set of 15 controls that are built for modern development pipelines where developers, pipelines and execution can happen anywhere in the world.
Control one: Restrict administrative access to CI/CD tools. Ensure that only authorized people can make administrative changes to the CI/CD system, which prevents unauthorized changes to pipeline definitions.
Control two: Only accept commits signed with a developer GPG key. Unsigned code commits are challenging, if not impossible, to trace and pose a risk to the integrity of the codebase.
Control three: Automation access keys expire automatically. By ensuring that access keys used by automation expire periodically, developers create a shorter window of attack when keys are compromised.
Control four: Reduce automation access to read-only. CI systems should have read-only access to source code repositories following the principle of least-privilege access.
Control five: Only dependencies from trusted registries can be used. By configuring the dependency manager to only allow connections to an authorized list of registries, attacks can be blunted by keeping malicious packages in public registries from entering the pipeline.
Control six: Any critical or high-severity vulnerability breaks the build. Supply chain attacks may introduce code with vulnerabilities into the software pipeline. Static application security testing (SAST) helps to identify serious security issues, including poor cryptographic practices, hard-coded credentials and injection vulnerabilities.
Control seven: Artifacts are stored in a repository in development, staging and production. This control helps to enforce the immutability of the artifacts so they can be compared in the development, staging and production repositories.
Control eight: Validate artifact digest. Before an artifact is deployed in any environment, its digest should be validated against the artifact in the repository to ensure that it has not been compromised.
Control nine: Pull requests require two reviewers (including one default reviewer) and a passing build to be merged. In addition to supporting good coding practices, this control also helps ensure that no commits are made without competent human oversight.
Control 10: Artifacts in higher repositories are signed. Requiring artifacts to be signed in a repository throughout the process ensures visibility and traceability for whatever is deployed to production.
Control 11: Available container images don’t have any high or critical vulnerabilities. Just as applications need to be tested for vulnerabilities before being placed in production, so do the container images into which they are packaged for deployment. Container images could have open source vulnerabilities if they contain open source software.
Control 12: Validate artifact signatures and digests. Validating the signature of the artifact against the digest ensures that the artifact was not tampered with in the repository and that the artifact being deployed is the same one that was tested.
Control 13: Scan deployed images in production. This helps to ensure that the prior controls were followed for all software in production.
Control 14: Validate Kubernetes resource manifests. If the resource manifests are tampered with, they could be tricked into deploying a container of the attacker’s choice.
Control 15: Ensure build environments are ephemeral and immutable. Build environments should be defined in code with automated creation and teardown and a fresh environment created for every build. Build hosts should not be accessible using interactive logins.
We believe this blueprint provides engineering teams with an actionable architecture that security teams can rally behind and support. By adopting these standards, engineering teams are promised the delivery of assured software at lower risk of supply chain tampering, reduction of attacks during development and manipulation in staging and production.
Here’s what it looks like:
To learn more about the suggested blueprint, read our GitHub post about the project. Our goal is to prioritize speed and agility for software development while incorporating a security-always mindset.