Background & Problem Statement:
I am working with curated base images that are patched and secured internally before being made available for application teams. These curated images are stored in an internal Artifactory registry and are referenced as a FROM in downstream application builds.
Example scenario:
Curated base image → curated_image:123 (has a manifest.json with secure patches)
App team’s image → app_image:456 (built using FROM curated_image:123, adding new layers)
I want to track lineage between these images to ensure that application teams are actually using the latest curated base image.
What I’ve Tried:
Pulled manifests for both images from the internal registry and compared the fsLayers.
Observed a common SHA256 layer:
"fsLayers": [ { "blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4" } ]
However, this SHA256 appears in multiple images and might be a generic placeholder (possibly an empty layer used for ENV or metadata).
Compared config.digest from the manifest.json, but it changes as new layers are added by the application teams.
My Questions What is the most reliable way to identify that an application image (e.g., app_image:456) is built from a specific curated base image (curated_image:123)?
Should I track parent image digests, history metadata, or another attribute?
Is there a standard best practice for enforcing and verifying base image lineage in a private Artifactory registry?
Any insights, especially from those managing internal container image curation pipelines, would be greatly appreciated!
Background & Problem Statement:
I am working with curated base images that are patched and secured internally before being made available for application teams. These curated images are stored in an internal Artifactory registry and are referenced as a FROM in downstream application builds.
Example scenario:
Curated base image → curated_image:123 (has a manifest.json with secure patches)
App team’s image → app_image:456 (built using FROM curated_image:123, adding new layers)
I want to track lineage between these images to ensure that application teams are actually using the latest curated base image.
What I’ve Tried:
Pulled manifests for both images from the internal registry and compared the fsLayers.
Observed a common SHA256 layer:
"fsLayers": [ { "blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4" } ]
However, this SHA256 appears in multiple images and might be a generic placeholder (possibly an empty layer used for ENV or metadata).
Compared config.digest from the manifest.json, but it changes as new layers are added by the application teams.
My Questions What is the most reliable way to identify that an application image (e.g., app_image:456) is built from a specific curated base image (curated_image:123)?
Should I track parent image digests, history metadata, or another attribute?
Is there a standard best practice for enforcing and verifying base image lineage in a private Artifactory registry?
Any insights, especially from those managing internal container image curation pipelines, would be greatly appreciated!
Share Improve this question edited 2 days ago Sharif asked Feb 7 at 19:54 SharifSharif 11 bronze badge New contributor Sharif is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct. 5 |1 Answer
Reset to default 0As a best practice, the OCI image-spec defines a few annotations that should be set on an image to make this task much easier:
org.opencontainers.image.base.digest
: Digest of the image this image is based on
org.opencontainers.image.base.name
: Image reference of the image this image is based on
When these annotations are included on app_image:456
, you would see org.opencontainers.image.base.name
set to curated_image:123
and can check if the current digest of curated_image:123
matches the value of org.opencontainers.image.base.digest
.
When that is not done (and it's rarely done today), the process to see if the base image has changed involves inspecting the manifest and config blob of the image and its base image. Note that there is no built-in way to identify the base image name/tag from an image, if that is not annotated, you need to discover this with external means. A base image simply imports the initial state of an image build, and then adds layers, and adjusts the config to make a new image that forked from the base.
The steps to compare the two involve:
- Recursively processing the image if it is a multi-platform image.
- Comparing the layer list to ensure all layers from the base image match the initial layer list of the target image (they must start from the beginning, with no insertions, deletions, or changes in order).
- Comparing the history entries in the image config to ensure all history lines from the base image match the initial history lines in the target image (this verifies no configuration changes were made in a new base image that wouldn't modify the base image layers).
When all of those match, the image is built from the current base image. All of those steps are included in my own regclient project in the regclient.ImageCheckBase method (source available). And the easy button for using that is to use regctl image check-base
:
regctl image check-base app_image:456 --base curated_image:123
docker pull
an image generally knows that it doesn't need to pull a layer it already has. – David Maze Commented Feb 7 at 21:48