Manifesto lets users store and query metadata for Docker images. This metadata can be information that you want to store about an image post-build - where labels are not sufficient.
The intention is that each piece of metadata could be signed using Notary. This means you can reliably get back the most recent version of that piece of metadata and know that it was put in place by someone with the authority to do so.
At the moment this is a Proof of Concept - feedback and ideas very welcome.
We automatically build binary executables for Mac, Linux and Windows, or you can rebuild from source. Whichever approach you take, you'll also need to set up credentials - see below.
Download the latest binary for your platform from the releases tab and unzip it.
You may find it easiest to move the binary into your path once you have downloaded it. For example
$ wget https://github.com/aquasecurity/manifesto/releases/download/<release tag>/manifesto-darwin-amd64.tar.gz
$ tar xf manifesto-darwin-amd64.tar.gz
$ cp bin/darwin/amd64/manifesto /us/local/bin
go get github.com/aquasecurity/manifesto
)go build .
In this release you will need to be logged in to the Docker Registry - do this with docker login
. This means that manifesto can execute docker commands directly.
In addition, since we are now using the Registry API directly to store and retrieve metadata in blobs, you need to pass in your username and password to manifesto itself. You can do this with the command line, environment variables REGISTRY_USERNAME and REGISTRY_PASSWORD, or by responding to prompts.
$ ./manifesto --help
Store, retrieve and list pieces of metadata alongside your container images in the registry.
Metadata is associated with specific images (by hash).
Usage:
manifesto [command]
Available Commands:
get Show metadata for the container image
help Help about any command
list List currently stored metadata for the container image
put Put metadata for the container image
Flags:
-h, --help help for manifesto
-p, --password string Registry password (can also be passed in with the env var REGISTRY_PASSWORD)
-u, --username string Registry username (can also be passed in with the env var REGISTRY_USERNAME)
-v, --verbose Send debug output to stderr
Use "manifesto [command] --help" for more information about a command.
By default (like Docker images) manifesto assumes the 'latest' tag if a tag is not given.
$ ./manifesto put myorg/imagetest something ~/temp.json
Storing metadata 'something' for 'myorg/imagetest:latest'
Metadata 'something' for 'myorg/imagetest:latest' stored at sha256:7be34480285971f16eed284b13fa7d417649f18c7d1af9b2de6970ce99e3cbbd
Updating manifesto for myorg/imagetest
Replacing 'something' metadata in manifesto for 'myorg/imagetest:latest'
$ ./manifesto list myorg/imagetest
Metadata types stored for image 'myorg/imagetest:latest':
something
$ ./manifesto get myorg/imagetest something
{
"key" : "value",
"createdBy" : "liz",
"number" : 56
}
In this proof of concept:
In v 0.0.1 the metadata was stored as separate images, tagged as _manifesto_metadata-type. This allowed us to build the initial prototype very easily, but it meant there were additional repository tags for each piece of metadata, which seems undesirable.
In this version we use the Registry API to store metadata directly in blobs, as shown in the diagram above. This will mean there will just be one additional tag in the repository, _manifesto.
As the metadata is stored in the same repository as the image itself, you can only store metadata for images you own. You could of course save a copy of a third-party image in your own repository, and store metadata alongside it.
Putting metadata into the registry itself allows us to leverage both existing technology and existing infrastructure. An organisation that stores images in its own on-premise registry can simply store metadata in it, and if they are using Notary again they can simply re-use the same deployment. The signing of metadata uses exactly the same process as the signing of images, so any existing audits and controls can be re-used.
The manifesto associated with a repository is built using a Dockerfile like this:
FROM scratch
ADD <filename> /data
Where
{
"images": [{
"image_digest": "70d2f067eb94ec8ab0530068a414d8dbe8c203244ae5d5ad4ba6eb1babd1c1c1",
"manifesto": [{
"type": "seccomp",
"digest": "sha256:a2fe22a6d44aa86432adad99481c3ad526ba35af2223df126620d20e38c70fac"
},
{
"type": "approvals",
"digest": "sha256:6ced8eb4e6a61639601e7073963ec04a80f70a11442157e1dd825f042879a6da"
},
{
"type": "contact",
"digest": "sha256:e896a0012a3450d9cef7e040eea8bed3fe06188957439fea501a65b62c65b4f1"
}
]
},
{
"image_digest": "51d2f067eb94ec8ab0531987a414d8dbe8c203244ae5d5ad4ba6eb1babd1d54a",
"manifesto": [{
"type": "seccomp",
"digest": "sha256:b2f72296d04ea36435adae99481c3ad526ba35af2223df126620d20e38c9763c"
},
{
"type": "documentation",
"digest": "sha256:9ce18eb4e6a66639601e7073963ec04aa0f70a11442157e1d9825f042879abb1"
}
]
}]
}
The type of each piece of metadata is simply an arbitrary string to identify that type of data. One possibility is to use standardized names (possibly as defined in the OCI image spec or similar) for the type to indicate that the associated data blob contains JSON in a standardized format (such as the vulnerability scanning report format).
When you pull a Docker image tagged, say, 1.4 you'll get whatever the latest signed version tagged 1.4 is. The tag can move between different images (i.e. with different digests) as updates are made, for example to update from 1.4.3 to 1.4.4.
For many types of image metadata (e.g. approval status, vulnerability scan report), a piece of metadata must be associated with a particular build i.e. identified by the digest.
When metadata is added, if signing is enabled the metadata blob gets signed in Notary, as does the manifesto with the references to the metadata blobs.
docker login
is sufficient for the credentials. It would be better to be consistent, and even better if there were a way of using the credentials from that docker login