SBOM (Software Bill of Materials) — Part II, Reports Using Syft and Grype.
Need Help?
The functionality discussed in this post, and so much more, are available via the SOCFortress platform. Let SOCFortress help you and your team keep your infrastructure secure.
Website: https://www.socfortress.co/
Contact Us: https://www.socfortress.co/contact_form.html
Intro
In cybersecurity, an SBOM (Software Bill of Materials) is a critical document that lists the components used in building a software application, including libraries, frameworks, and dependencies.
It’s like an “ingredient list” for software, showing the underlying open source and proprietary components that comprise a given piece of software. With it, organisations can better understand, manage, and secure their applications.
(See previous article here)
SBOM Report Creation Using Syft
Reference: https://github.com/anchore/syft
Syft is an open-source tool developed by Anchore designed to generate a Software Bill of Materials (SBOM) for container images and filesystems. It helps organisations gain visibility into the components of their software by identifying dependencies, libraries, and other third-party components, which are crucial for security and compliance purposes.
By generating SBOMs for your container images or software builds, Syft helps teams identify what third-party components they are using, and when combined with vulnerability scanning (using Grype), it helps identify known vulnerabilities within those components.
SBOMs generated by Syft help organisations comply with industry standards and regulatory requirements (e.g., the U.S. Executive Order on Cybersecurity, which mandates SBOM generation for software used by the government).
Many organisations are concerned about open-source software licenses. Syft’s SBOMs include license data for identified packages, making it easier to manage licensing risks and ensure compliance with licensing policies.
As supply chain attacks become more common, understanding what is in your software is crucial. Syft helps developers, security teams, and operations teams know exactly what components are used and their associated risks, improving the overall security posture.
Syft can be seamlessly integrated into CI/CD pipelines, allowing teams to generate SBOMs at every stage of software development. This helps enforce security checks and validate software integrity before deployment.
Syft’s features can be extended through APIs and custom workflows, making it a flexible tool for security automation.
Key Features of Syft
- SBOM Generation:
Syft can generate SBOMs in various formats, such as:
— CycloneDX (commonly used in security contexts)
— SPDX (for software package data exchange)
— Syft’s native format
The SBOM provides detailed metadata about the software components, including the package names, versions, licenses, and potential vulnerabilities (when used alongside vulnerability scanning tools).
- Works with Different Ecosystems:
Syft supports a wide range of software ecosystems and package types. Some of the most commonly used ecosystems supported are:
— Docker and OCI-compliant container images
— Java (JAR, WAR, EAR files)
— JavaScript (NPM packages)
— Python (Pip, Poetry)
— Ruby (Gem packages)
— Go modules
— Rust (Cargo)
— .NET (NuGet packages)
— Filesystem scanning - Integration with CI/CD Pipelines:
Syft can be integrated into continuous integration/continuous deployment (CI/CD) pipelines to automatically generate an SBOM for every software build or container image. This ensures real-time visibility into the software supply chain and enables organizations to monitor and manage security risks early in the development process. - Container Image Support:
Syft can inspect and analyze container images, such as those stored in Docker registries, and generate SBOMs for these images. This is useful for both developers building containerized applications and security teams monitoring container deployments in production. - Command-Line Interface (CLI):
Syft is built as a command-line tool, making it simple and lightweight to integrate into workflows. You can run Syft commands directly on your local machine or integrate them into automation scripts. - Support for Other Tools:
Syft is often used alongside Grype, another tool by Anchore that performs vulnerability scanning on SBOMs. When used together, Syft and Grype allow organizations to identify vulnerable packages and components in their SBOMs.
Vulnerability Report Using Grype
Reference: https://github.com/anchore/grype
Grype is an open-source vulnerability scanner for container images and file systems. It helps developers and security professionals identify known vulnerabilities in their software supply chains by scanning Docker images, containers, and files for vulnerabilities. Developed by Anchore, Grype works by comparing the software packages in an image or filesystem with known vulnerabilities in various databases, such as the National Vulnerability Database (NVD), GitHub Advisories, and others.
Grype helps developers and security teams identify vulnerabilities early in the development cycle, protecting containerised applications from known exploits.
With its CI/CD integration, Grype makes vulnerability scanning an automated part of the software development lifecycle, ensuring continuous security.
As an open-source project under Anchore, Grype is continuously updated with the latest vulnerability data and features. It has an active community and is a trusted tool for vulnerability management in the cloud-native space.
Features
- Comprehensive Vulnerability Scanning:
— Grype scans container images, filesystems, and individual software packages for known vulnerabilities, using public vulnerability databases.
— It supports a wide range of package managers (e.g., APT, RPM, APK, NPM, and Python’s PIP) and OS distributions. - Multiple Sources for Vulnerability Data:
— Grype pulls vulnerability data from several sources, including the NVD, Alpine SecDB, Red Hat UBI, GitHub Security Advisories, and more. This makes it effective for identifying vulnerabilities across different ecosystems. - SBOM Integration with Syft:
— Grype integrates seamlessly with Syft, another tool by Anchore that generates Software Bill of Materials (SBOM). You can use Syft to generate a list of software components (like installed packages), and Grype will scan that list for vulnerabilities.
— This approach ensures comprehensive scanning with visibility into what software is running within an image. - Multiple Output Formats:
— Grype provides flexibility in how scan results are output, supporting multiple formats:
— CycloneDX (XML/JSON): A standardized format for sharing vulnerability data in a machine-readable way.
— SPDX (JSON): Another popular format for reporting vulnerabilities.
— SARIF: Static Analysis Results Interchange Format, suitable for integration with static code analysis tools.
— JSON: To get a detailed, raw report that can be integrated into other workflows or further analyzed. - Continuous Integration/Continuous Deployment (CI/CD) Integration:
— Grype can be integrated into CI/CD pipelines to automatically scan container images for vulnerabilities during the development and deployment process. This helps catch vulnerabilities before images are pushed to production, providing an extra layer of security in DevOps workflows. - Customizable Data Sources:
— Users can configure Grype to use their own vulnerability data feeds or customize which feeds are used in a scan. - CLI-based and Easy to Use:
— Grype is lightweight and easy to install. It runs as a command-line tool, which makes it simple to integrate into existing systems and automation workflows.
Syft and Grype in action
Using python Flask we can create a quick web server and form to input the name of the docker image for which we want to generate SBOM and vulnerability scan reports.
Here are the steps:
Install Syft:
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
Install Grype:
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
Install Flask:
pip install Flask
Create python “app.py”
from flask import Flask, render_template, request, send_file
import os
import subprocess
app = Flask(__name__)
# Ensure a directory for storing output files exists
OUTPUT_DIR = "reports"
if not os.path.exists(OUTPUT_DIR):
os.makedirs(OUTPUT_DIR)
# Define available formats for Syft and Grype
SYFT_FORMATS = [
"syft-json",
"cyclonedx-xml",
"cyclonedx-xml@1.5",
"cyclonedx-json",
"cyclonedx-json@1.5",
"spdx-json",
"spdx-json@2.2"
]
GRYPE_FORMATS = [
"cyclonedx",
"cyclonedx-json",
"json",
"sarif"
]
@app.route('/')
def index():
return render_template('index.html', syft_formats=SYFT_FORMATS, grype_formats=GRYPE_FORMATS)
@app.route('/generate', methods=['POST'])
def generate_reports():
image_id = request.form['image_id']
syft_format = request.form['syft_format']
grype_format = request.form['grype_format']
if not image_id:
return "Error: Docker image ID is required.", 400
# Generate file paths for Syft and Grype outputs
syft_output_file = os.path.join(OUTPUT_DIR, f"{image_id.replace(':', '_')}_syft_report.{syft_format.split('-')[-1]}")
grype_output_file = os.path.join(OUTPUT_DIR, f"{image_id.replace(':', '_')}_grype_report.{grype_format.split('-')[-1]}")
try:
# Run Syft command
syft_command = f"syft {image_id} -o {syft_format} > {syft_output_file}"
subprocess.run(syft_command, shell=True, check=True)
# Run Grype command
grype_command = f"grype {image_id} -o {grype_format} > {grype_output_file}"
subprocess.run(grype_command, shell=True, check=True)
except subprocess.CalledProcessError as e:
return f"Error while generating the report: {e}", 500
# Provide download links for both Syft and Grype reports
return f"""
Reports generated successfully!<br>
<a href='/download/{os.path.basename(syft_output_file)}'>Download Syft report</a><br>
<a href='/download/{os.path.basename(grype_output_file)}'>Download Grype report</a>
"""
@app.route('/download/<filename>')
def download_file(filename):
filepath = os.path.join(OUTPUT_DIR, filename)
if os.path.exists(filepath):
return send_file(filepath, as_attachment=True)
else:
return "File not found!", 404
if __name__ == '__main__':
app.run(debug=True)
HTML template:
from flask import Flask, render_template, request, send_file
import os
import subprocess
app = Flask(__name__)
# Ensure a directory for storing output files exists
OUTPUT_DIR = "reports"
if not os.path.exists(OUTPUT_DIR):
os.makedirs(OUTPUT_DIR)
# Define available formats for Syft and Grype
SYFT_FORMATS = [
"syft-json",
"cyclonedx-xml",
"cyclonedx-xml@1.5",
"cyclonedx-json",
"cyclonedx-json@1.5",
"spdx-json",
"spdx-json@2.2"
]
GRYPE_FORMATS = [
"cyclonedx",
"cyclonedx-json",
"json",
"sarif"
]
@app.route('/')
def index():
return render_template('index.html', syft_formats=SYFT_FORMATS, grype_formats=GRYPE_FORMATS)
@app.route('/generate', methods=['POST'])
def generate_reports():
image_id = request.form['image_id']
syft_format = request.form['syft_format']
grype_format = request.form['grype_format']
if not image_id:
return "Error: Docker image ID is required.", 400
# Generate file paths for Syft and Grype outputs
syft_output_file = os.path.join(OUTPUT_DIR, f"{image_id.replace(':', '_')}_syft_report.{syft_format.split('-')[-1]}")
grype_output_file = os.path.join(OUTPUT_DIR, f"{image_id.replace(':', '_')}_grype_report.{grype_format.split('-')[-1]}")
try:
# Run Syft command
syft_command = f"syft {image_id} -o {syft_format} > {syft_output_file}"
subprocess.run(syft_command, shell=True, check=True)
# Run Grype command
grype_command = f"grype {image_id} -o {grype_format} > {grype_output_file}"
subprocess.run(grype_command, shell=True, check=True)
except subprocess.CalledProcessError as e:
return f"Error while generating the report: {e}", 500
# Provide download links for both Syft and Grype reports
return f"""
Reports generated successfully!<br>
<a href='/download/{os.path.basename(syft_output_file)}'>Download Syft report</a><br>
<a href='/download/{os.path.basename(grype_output_file)}'>Download Grype report</a>
"""
@app.route('/download/<filename>')
def download_file(filename):
filepath = os.path.join(OUTPUT_DIR, filename)
if os.path.exists(filepath):
return send_file(filepath, as_attachment=True)
else:
return "File not found!", 404
if __name__ == '__main__':
app.run(debug=True)
Kick off the app.
As part of the web form we can select the output format, as shown above.
Syft Formats:
- syft-json: Use this to get as much information out of Syft as possible!
- clonedx-xml: A XML report conforming to the CycloneDX 1.6 specification.
- cyclonedx-xml@1.5: A XML report conforming to the CycloneDX 1.5 specification.
- cyclonedx-json: A JSON report conforming to the CycloneDX 1.6 specification.
- cyclonedx-json@1.5: A JSON report conforming to the CycloneDX 1.5 specification.
- spdx-json: A JSON report conforming to the SPDX 2.3 JSON Schema. spdx-json@2.2: A JSON report conforming to the SPDX 2.2 JSON Schema.
Grype formats:
- cyclonedx: An XML report conforming to the CycloneDX 1.6 specification.
- cyclonedx-json: A JSON report conforming to the CycloneDX 1.6 specification.
- json: Use this to get as much information out of Grype as possible!
- sarif: Use this option to get a SARIF report (Static Analysis Results Interchange Format).
After submitting, reports will be available for download:
From the Grype report (vulnerabilities):
Need Help?
The functionality discussed in this post, and so much more, are available via the SOCFortress platform. Let SOCFortress help you and your team keep your infrastructure secure.
Website: https://www.socfortress.co/
Contact Us: https://www.socfortress.co/contact_form.html