Tern
Tern is a software composition analysis tool and Python library that generates a Software Bill of Materials for container images and Dockerfiles. The SBOM that Tern generates will give you a layer-by-layer view of what's inside your container in a variety of formats including human-readable, JSON, HTML, SPDX and more.
Install / Use
/learn @tern-tools/TernREADME

Welcome to the Tern Project
Tern is a software package inspection tool that can create a Software Bill of Materials (SBOM) for containers. It's written in Python3 with a smattering of shell scripts.
Table of Contents
- Introduction
- Getting Started
- Using Tern
- Report Formats
- Extensions
- Running tests
- Project Status
- Contributing
What is Tern?<a name="what-is-tern">
Tern is an inspection tool to find the metadata of the packages installed in a container image. The overall operation looks like this:
- It analyzes the first layer of the container image to collect information like distro type, package format, and package managers.
- It then executes scripts from the "command library" in a chroot environment to collect information about packages installed in that layer.
- With that information as a starting point, it continues to analyze the subsequent layers in the container image.
- Once done, it generates a report of packages with their metadata. Several formats are available. The report, in its default format, provides a layer by layer, explanation of the various software components imported. If a Dockerfile is provided, the report indicates the Dockerfile lines corresponding to each of the file system layers.
Tern gives you a deeper understanding of your container's bill of materials so you can make better decisions about your container based infrastructure, integration and deployment strategies. It's also a good tool if you are curious about the contents of the container images you have built.

Getting Started<a name="getting-started"/>
GitHub Action<a name="github-action"/>
A GitHub Action is available if you just want to scan Docker container images to find the Base OS and packages installed. Please contribute changes here. Thanks to Jeroen Knoops @JeroenKnoops for their work on this.
Getting Started on Linux<a name="getting-started-on-linux">
If you have a Linux OS you will need a distro with a kernel version >= 4.0 (Ubuntu 16.04 or newer or Fedora 25 or newer are good selections) and will need to install the following requirements:
- Git (Installation instructions can be found here: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
- attr (sudo apt-get install attr or sudo dnf install attr)
- Python 3.6 or newer (sudo apt-get install python3.6(3.7) or sudo dnf install python36(37))
- Pip (sudo apt-get install python3-pip).
- jq (sudo apt-get install jq or sudo dnf install jq)
- skopeo (See here for installation instructions or building from source)
Some distro versions have all of these except attr, jq, and/or skopeo preinstalled. attr and jq are common utilities and are available via the package manager. skopeo has only recently been packaged for common Linux distros. If you don't see your distro in the list, your best bet is building from source, which is reasonably straightforward if you have Go installed.
For analyzing Dockerfiles and to use the "lock" function
- Docker CE (Installation instructions can be found here: https://docs.docker.com/engine/installation/#server)
NOTE: We do not provide advice on the usage of Docker Desktop
Once installed, make sure the docker daemon is running.
Create a python3 virtual environment:
python3 -m venv ternenv
cd ternenv
NOTE: Your OS might distribute each Python version separately. For example, on Ubuntu LTS, Python 2.7 is linked to python2 and Python 3.6 is linked to python3. I develop with Python 3.7 which is installed separately with no symlinks. In this case, I use the binary. The binaries are usually installed in /usr/bin/python.
Activate the virtual environment:
source bin/activate
NOTE: This specific activate script only works for Bash shells. If you need to activate a Fish Shell or C Shell you should use source bin/activate.fish or source bin/activate.csh, respectively.
Install tern:
pip install tern
Run Tern:
tern report -o output.txt -i debian:buster
Getting Started with Docker<a name="getting-started-with-docker">
Docker is the most widely used tool to build and run containers. If you already have Docker installed, you can run Tern by building a container with the Dockerfile provided.
Clone this repository:
git clone https://github.com/tern-tools/tern.git
Build the Docker image (called ternd here). You may need to use sudo:
docker build -f docker/Dockerfile -t ternd .
This will install the latest release of tern using pip.
If you want to build a Docker image containing the latest changes to tern, run:
python setup.py sdist
docker build -f ci/Dockerfile -t ternd .
NOTE: By default, Tern will run with logging turned on. If you would like to silent the terminal output when running the ternd container, make the following change to the Dockerfile ENTRYPOINT before building:
--- a/Dockerfile
+++ b/Dockerfile
-ENTRYPOINT ["tern"]
+ENTRYPOINT ["tern", "-q"]
Run the ternd container image
docker run --rm ternd report -i debian:buster
If you are using this container to analyze Dockerfiles and to use the "lock" feature, then you must volume mount the docker socket. We have a convenience script which will do that for you.
./docker_run.sh ternd "report -i debian:buster" > output.txt
To produce a json report run
./docker_run.sh ternd "report -f json -i debian:buster"
Tern is not distributed as Docker images yet. This is coming soon. Watch the Project Status for updates.
WARNING: If using the --driver fuse or --driver overlay2 storage driver options, then the docker image needs to run as privileged.
docker run --privileged -v /var/run/docker.sock:/var/run/docker.sock ternd --driver fuse report -i debian:buster
You can make this change to the docker_run.sh script to make it easier.
Creating a Kubernetes Job<a name="k8s-job">
A Tern container can be deployed on Kubernetes as a Job. However, a host mount is required to retrieve the reports. We will describe below how to create a Kubernetes Job within minikube.
To install minikube, follow these instructions. If using a virtual machine manager, make sure it supports volume mounts. We will be using VirtualBox in this example.
Download the existing Tern Dockerfile
wget https://raw.githubusercontent.com/tern-tools/tern/main/docker/Dockerfile
Start minikube
minikube start --driver=virtualbox
Use minikube to build the Tern container image
minikube image build -t tern:test -f Dockerfile .
Once build has completed, you should see the image by running minikube image ls. It should look something like docker.io/library/tern:test.
We are now ready to create a Job. You can modify the following YAML according to your host's filesystem:
apiVersion: batch/v1
kind: Job
metadata:
name: tern
spec:
template:
spec:
restartPolicy: Never
containers:
- image: docker.io/library/tern:test
# in order run the job for other containers, replace the "-i" argument here
command: ["tern", "report", "-i", "docker.io/library/debian:buster", "-o", "/host/report.txt"]
name: tern-example
volumeMounts:
- name: host-mount
mountPath: /host # this path exists in the pod
volumes:
- name: host-mount # create a corresponding directory on the host
hostPath:
path: /path/to/tern/reports # this path must exist on the host
We can now deploy Tern on Kubernetes
minikube kubectl -- apply -f tern-example.yaml
To check the status of the Job, you can run `minikube kubectl -- describe job
