Base and Parent Images
A Docker or OCI image is composed of layers. Some of the layers are created during a build process such as following instructions in a Dockerfile. But many of the layers will come from previously built images. These images likely come from a container team at your organization, or maybe build directly on images from a Linux distribution vendor. In some cases this chain could be many images deep as various teams add standard software or configuration.
Docker uses the FROM clause to denote an image to use as a basis for building a new image. The image provided in this clause is known by Docker as the Parent Image, but is commonly referred to as the Base Image. This chain of images built from other images using the FROM clause is known as an Image’s ancestry.
Note Docker defines Base Image as an image with a
FROM SCRATCHclause. Anchore does NOT follow this definition, instead following the more common usage where Base Image refers to the image that a given image was built from.
Example Ancestry
The following is an example of an image with multiple ancestors
A base distro image, for example debian:10
FROM scratch
...
A framework container image from that debian image, for example a node.js image let’s call mynode:latest
FROM debian:10
# Install nodejs
The application image itself built from the framework container, let’s call it myapp:v1
FROM mynode:latest
COPY ./app /
...
These dockerfiles generate the following ancestry graph:
graph debian:10-->|parent of|mynode:latest mynode:latest-->|parent of|myapp:v1
Where debian:10 is the parent of mynode:latest which is the parent of myapp:v1
Anchore compares the layer digests of images that it knows about to determine an images ancestry. This ensures that the exact image used to build a new image is identified.
Given our above example, we may see the following layers for each image. Note that each subsequent image is a superset of the previous images layers
block-beta
columns 5
block:debian_block
columns 1
debian["debian:10"]
style debian stroke-width:0px
debian_layer1["sha256:abc"]
debian_layer2["sha256:def"]
space
space
end
space
block:mynode_block
columns 1
mynode_name["mynode:latest"]
style mynode_name stroke-width:0px
mynode_layer1["sha256:abc"]
mynode_layer2["sha256:def"]
mynode_layer3["sha256:123"]
space
end
space
block:myapp_block
columns 1
myapp_name["myapp:v1"]
style myapp_name stroke-width:0px
myapp_layer1["sha256:abc"]
myapp_layer2["sha256:def"]
myapp_layer3["sha256:123"]
myapp_layer4["sha256:456"]
end
mynode_name -- "FROM" --> debian
debian_layer1 --> mynode_layer1
mynode_layer1 --> debian_layer1
debian_layer2 --> mynode_layer2
mynode_layer2 --> debian_layer2
myapp_name -- "FROM" --> mynode_name
mynode_layer1 --> myapp_layer1
myapp_layer1 --> mynode_layer1
mynode_layer2 --> myapp_layer2
myapp_layer2 --> mynode_layer2
mynode_layer3 --> myapp_layer3
myapp_layer3 --> mynode_layer3Ancestry within Anchore
Anchore automatically calculates an image’s ancestry as images are scanned. This works by comparing the layer digests of each image to calculate the entire chain of images that produced a given image. The entire ancestry can be retrieved for an image through the GET /v2/images/{image_digest}/ancestors API. See the API docs for more information on the specifics.
Base Image
It is often useful to compare an image with another image in its ancestry. For example to filter out vulnerabilities that are present in a “golden image” from a platform team and only showing vulnerabilities introduced by the application being built on the “golden image”.
Controlling the Base Image
Users can control which ancestor is chosen as the base image by marking the desired image(s) with a special annotation anchore.user/marked_base_image. The annotation should be set to a value of true, otherwise it will be ignored. This annotation is currently restricted to users in the “admin” account.
If an image with this annotation should no longer be considered a Base Image then you must update the annotation to false, as it is not currently possible to remove annotations.
Usage of this annotation when calculating the Base Image can be disabled by setting services.policy_engine.enable_user_base_image to false in the configuration file (see deployment specific docs for configuring this setting).
Anchorectl Example
You can add an image with this annotation using AnchoreCTL with the following:
anchorectl image add anchore/test_images:ancestor-base -w --annotation "anchore.user/marked_base_image=true"
If an image should no longer be considered a Base Image you can update the annotation with:
anchorectl image add anchore/test_images:ancestor-base --annotation "anchore.user/marked_base_image=false"
Calculating the Base Image
Anchore will automatically calculate the Base Image from an image’s ancestry using the closest ancestor. From our example above, the Base Image for myapp:v1 is mynode:latest.
The first ancestor with this annotation will be used as the Base Image, if no ancestors have this annotation than it will fall back to using the closest ancestor (the Parent Image).
The rules for determining the Base Image are encoded in this diagram
graph
start([start])-->image
image[image]
image-->first_parent_exists
first_parent_exists{Does this image have a parent?}
first_parent_exists-->|No|no_base_image
first_parent_exists-->|yes|first_parent_image
first_parent_image[Parent Image]
first_parent_image-->config
config{User Base Annotations Enabled in configuration?}
config-->|No|base_image
config-->|yes|check_parent
check_parent{Parent has anchore.user/marked_base_image: true annotation}
check_parent-->|No|parent_exists
parent_exists{Does the parent image have a parent?}
parent_exists-->|Yes|parent_image
parent_image[/Move to next Parent Image/]
parent_image-->check_parent
parent_exists-->|No|no_base_image
check_parent-->|Yes|base_image
base_image([Found Base Image])
no_base_image([No Base Image Exists])Using the Base Image
The Policy evaluation and Vuln Scan APIs have an optional base_digest parameter that is used to provide comparison data between two images. These APIs can be used in conjunction with the ancestry API to perform comparisons to the Base Image so that application developers can focus on results in their direct control. As of Enterprise v5.7.0, a special value auto can also be specified for this parameter to have the system automatically determine which image to use in the comparison based on the above rules.
To read more about the base comparison features, jump to
In addition to these user facing APIs, a few parts of the system utilize the Ancestry information.
- The Ancestry Policy Gate uses the Base Image rules to determine which image to evaluate against
- Reporting uses the Base Image to calculate the “Inherited From Base” column for vulnerabilities
- The UI displays the Base Image and uses it for Policy Evaluations and Vulnerability Scans
Additional notes about ancestor calculations
An image B is only a child of Image A if All of the layers of Image A are present in Image B.
For example, mypython and mynode represent two different language runtime images built from a debian base. These two images are not ancestors of each other because the layers in mypython:latest are not a superset of the layers in mynode:latest, nor the other way around.
block-beta
columns 3
block:mypython_block
columns 1
mypython_name["mypython:latest"]
style mypython_name stroke-width:0px
mypython_layer1["sha256:abc"]
mypython_layer2["sha256:def"]
mypython_layer3["sha256:456"]
end
space
block:mynode_block
columns 1
mynode_name["mynode:latest"]
style mynode_name stroke-width:0px
mynode_layer1["sha256:abc"]
mynode_layer2["sha256:def"]
mynode_layer3["sha256:123"]
end
mypython_layer1 --> mynode_layer1
mynode_layer1 --> mypython_layer1
mypython_layer2 --> mynode_layer2
mynode_layer2 --> mypython_layer2
mypython_layer3 -- "X" --> mynode_layer3But these images could be based on a 3rd image which is made up of the 2 layers that they share. If Anchore knows about this 3rd image it would show up as an ancestor for both mypython and mynode.
The Anchore UI would identify the debian:10 image as an ancestor of the mypython:latest and the mynode:latest images. But we do not currently expose child ancestors, so we would not show the children of the debian:10 image.
block-beta
columns 5
block:mypython_block
columns 1
mypython_name["mypython:latest"]
style mypython_name stroke-width:0px
mypython_layer1["sha256:abc"]
mypython_layer2["sha256:def"]
mypython_layer4["sha256:456"]
end
space
block:debian_block
columns 1
debian["debian:10"]
style debian stroke-width:0px
debian_layer1["sha256:abc"]
debian_layer2["sha256:def"]
space
end
space
block:mynode_block
columns 1
mynode_name["mynode:latest"]
style mynode_name stroke-width:0px
mynode_layer1["sha256:abc"]
mynode_layer2["sha256:def"]
mynode_layer3["sha256:123"]
end
mynode_name -- "FROM" --> debian
debian_layer1 --> mynode_layer1
mynode_layer1 --> debian_layer1
debian_layer2 --> mynode_layer2
mynode_layer2 --> debian_layer2
mypython_name -- "FROM" --> debian
debian_layer1 --> mypython_layer1
mypython_layer1 --> debian_layer1
debian_layer2 --> mypython_layer2
mypython_layer2 --> debian_layer2Last modified August 14, 2025