Cyber Security
Differences between Including Software Libraries vs Containers
Navigating Libraries vs. Containers - Insights on Versioning, Code Scanning, and Configuration Safeguards for Developers and Security Teams
Navigating Libraries vs. Containers - Insights on Versioning, Code Scanning, and Configuration Safeguards for Developers and Security Teams
Software has evolved from the simplicity of running programs on a single machine to the complexity of cloud deployment. Software evolution is nothing short of revolutionary. The progression from single machines to cloud deployments reflects a constant drive for efficiency, scalability and adaptability for developers, teams and and companies.
As applications have become more modular with microservices, they rely on various external libraries, (open-source) applications and components. Ensuring that these dependencies are compatible and using the correct version becomes critical. Coordinating compatible versions across services is vital to avoid integration issues. Version mismatches can lead to communication failures, security vulnerabilities, or unexpected behavior.
With the adoption of CI/CD practices, software is continuously delivered, tested and deployed. The rapid pace requires meticulous versioning to track changes and ensure that updates don’t introduce regressions or break existing functionalities. This is further complicated with the adoption of containers. Containers offer isolation of components, but introduce their own versioning challenges.
Software verification and static application security testing (SAST) have evolved to cover a wide range of code usage issues including code quality, compliance violations, architectural problems and the correct use of components and libraries. There are pieces of software that can be included in projects and applications that can be used “the wrong way”. Like a knife can be used both for cooking as well as murder. The former (cooking) is the intended use, the latter (murder) is not (but we’ll leave that analysis up to you). It’s pretty clear at this point you should be using a code scanner (we use semgrep but this might not work for you).
Modern package managers, like npm for Node.js or pip for Python, simplify dependency management. And CVE scanners can highlight missing or incompatible dependencies. Package managers and scanners require careful attention to version specifications, as ambiguous or overly permissive version constraints can lead to unintended and potentially risky updates and security concerns. The CVEs are not necessarily introduced by the software library itself, but could be introduced through sub-dependencies.
The CVEs are not necessarily always introduced by the included software library itself, but could also be through sub-dependencies. Hence, a seemingly in-between update may fix a security-related issue, and this is another argument why staying up to date is important. For many companies these in-between updates are ignored, and versions are allowed to rot as long as “it works”. Updating software dependencies is less of a headache when past investments in CI/CD result in fuller test coverage. The test coverage allows for risk assessment and impact for all updates and upgrades.
Proper versioning is essential for addressing security vulnerabilities. Outdated libraries or components may have known vulnerabilities that can be exploited. Software includes open source libraries and applications. And most open-source projects may be subject to CVEs over time. To counter the risk, teams require a good software updating strategy. Furthermore, the usage (and foremost the correct usage) may also change over time, and it is important to stay up to date, as otherwise, in the case of a CVE, an update may take longer and keeps the company vulnerable.
Let's imagine a scenario where a developer is working on a web application and decides to include a third-party container that provides user authentication services. In this case, the container comes with default settings that are not secure by industry standards. The developer, focused on quickly integrating the authentication container, overlooks the need to customize the default configurations. The container, in its default state, might have weak password policies, allow insecure communication, or have unnecessary open ports. These oversights can lead to significant security vulnerabilities.
Configuration is tightly intertwined with versioning and correct use in software development, especially in containerized and cloud-native environments. Properly managing and versioning configurations ensures a reliable, reproducible and secure deployment process. Configuring software running inside a container is usually done by including or overwriting a configuration file. For reproducibility, the configuration file should also be part of your code repository. Getting started can be overwhelming given the HUGE lis of static application security testing tools for different languages and different platforms. We’ve tried to provide an in-depth example on how to extract the configuration files and include them directly in your infrastructure (our project shows hardening a React/Node.js project including linting, code scanning and configuration scanning).
What we’ve seen is that automated scanning has become critical. This means we need tools that analyze codebases for known vulnerabilities. With containers you need to pay attention to the correct use (code scanning), version attention (CVEs and dependency scanning), and the configuration (CoGuard).
Other companies have been working on generating a software bill of materials (SBOM). But in a world of modern deployments, many are leaving out a critical part of their software supply chain security, their infrastructure. The SBOM is a comprehensive list of the components including third-party and open source code used in building the software (aka the dependencies). We also need to pay attention to the dependencies in containers, and how cloud infrastructure is managed and secured.
At CoGuard, we are exploring your infra from the configuration files up. We start by looking for the software specified in your IaC repository or live in your production cloud environments (read-only) and we search for the configuration files and their metadata. We see containers and the software configured to run inside each container and the associated configuration files. The config files includes cloud configurations, container-orchestration configurations, container configurations and the application configurations (for the applications we support). Then we run a scan for security best practices, misconfigurations and vulnerabilities. Our reports are the scan results. The collection of the configuration files and metadata is a type of, well our first attempt at an IBoM.
Let's consider an instance where we procure an EKS cluster from AWS. Within this, details about the Kubernetes version, the exposure level of specific endpoints, and other relevant information are documented as part of the Infrastructure Bill of Materials (IBOM).
In the process of defining containers and their orchestration, we utilize Docker and YAML files. The IBOM encompasses not only the specifications of containers but also crucial networking and storage details. Additionally, it includes information about the software incorporated into Docker files, forming the basis for compiling Docker images.
During the creation of Docker files, certain software installations might allow for configuration. The configuration specifics of these software components are integral to the IBOM, as they define essential elements such as access controls and pertinent communication details.
It's crucial to emphasize the significance of this thorough examination of the infrastructure. We've observed instances where individuals may halt their efforts after the initial step, leaving them vulnerable to potential data breaches.
You can get started by installing CoGuard and generating a manifest.
This will show you the configuration files in your IaC or build repository. Or you can create a manifest of your cloud configurations: