# Build, sign, push and verify images as OCI image layout ## Background Do you trust your container registries? Nowadays, users push the container images in the registry first, then sign the container image. What will happen if the registries are compromised? You could sign something that is not what you want to sign. The worst thing is that users can verify the container image successfully and use it in production. Sign images as OCI image layout is a new and creative way, which enable signing images on local disk before pushing them to the remote registry, thus the integrity of the images are secured. ## What is a OCI image layout? OCI image layout is a directory structure that contains files and folders that refer to an OCI image. OCI image layout is defined in [OCI image spec](https://github.com/opencontainers/image-spec/blob/v1.1.0-rc2/image-layout.md). ## How can I create OCI image layout? ### Use container image builder (Option 1) Use `docker buildx` to output the image that is built in the form of OCI Image Layout on local disk. 1. Create a Dockerfile ```text FROM alpine CMD echo 'hello world!' ``` 2. Build and save image in the form of OCI image layout on disk ```shell docker buildx create --use docker buildx build . -f Dockerfile -o type=oci,dest=hello-world.tar -t hello-world:v1 ``` In this example, `docker buildx build` saved the image in the form of OCI image layout as a tar file named `hell-world.tar`. The OCI image layout could also be in the form of a directory. For example, ```shell mkdir hello-world tar -xf ./hello-world.tar -C hello-world ``` ### Copy remote image to the disk in the form of OCI image layout (Option 2) If users already store the images in a remote registry, there are tools to copy the remote images to the disk in the form of OCI image layout. For example, ```shell oras cp localhost:5000/hello-world:v1 --to-oci-layout ./hello-world ``` > NOTE: use flag `-r` to copy both an image and its referrers, for example signatures ## User Scenario ### Sign and verify OCI images on local disk Pre-conditaion: - Save the OCI images on local disk as OCI image layout directory - The flag `--oci-layout` and `--scope` are experiemntal, make sure to set NOTATION_EXPERIMENTAL varaible ```shell export NOTATION_EXPERIMENTAL=1 ``` Steps: 1. Sign the image as OCI image layout on disk ```shell notation cert generate-test wabbit-networks.io --default notation sign --oci-layout ./hello-world:v1 ``` > NOTE: signatures are stored in the same OCI image layout directory, and associated with OCI image. 2. List signatures associated to the image ```shell notation list --oci-layout ./hello-world:v1 ``` Output example: ``` ./hello-world@sha256:a08753c0c7bcdaaf5c2fdb375f68e860c34bffb146368982c201d41769e1763c └── application/vnd.cncf.notary.signature └── sha256:0283100f21395c4422eeea8925a0677a46704c054d7eca04d5f47991b3dd9c19 ``` 3. Verify the image against signatures. ```shell notation verify --oci-layout ./hello-world:v1 --scope "local/hello-world" ``` > NOTE: The flag `--scope` is experiemntal, which is used to specify which trust policy is used for verification. The value is the value set for property `registryScopes`. An example of trustpolicy.json ```jsonc { "version": "1.0", "trustPolicies": [ { "name": "local-images-policy", "registryScopes": [ "local/hello-world" ], "signatureVerification": { "level" : "strict" }, "trustStores": [ "ca:wabbit-networks.io" ], "trustedIdentities": [ "*" ] } ] } ``` ### Sign OCI images on local disk, push OCI images to a remote registry and verify OCI images stored in the registry Pre-conditaion: - Save the OCI images on local disk as OCI image layout directory - Download latest version of [ORAS CLI](https://github.com/oras-project/oras/releases) - The flag `--oci-layout` and `--scope` are experiemntal, make sure to set NOTATION_EXPERIMENTAL varaible ```shell export NOTATION_EXPERIMENTAL=1 ``` Steps: 1. Sign the image as OCI image layout on local disk ```shell notation cert generate-test wabbit-networks.io --default notation sign --oci-layout ./hello-world:v1 ``` 2. List signatures associated to the image ```shell notation list --oci-layout ./hello-world:v1 ``` 3. (Optional) Verify the image against signatures locally. ```shell notation verify --oci-layout ./hello-world:v1 --scope "localhost:5000/hello-world" ``` 4. Push the image from local to a remote registry ```shell oras cp ./hello-world:v1 --from-oci-layout -r localhost:5000/hello-world:v1 ``` > NOTE: Make sure flag `-r` is used, so that the signatures will be copied together with the image. 5. List signatures from remote registry ```shell notation list localhost:5000/hello-world:v1 ``` You should see the signatures pushed from local to remote as well. 6. Verify the image in remote registry before deployed in to the system. ```shell notation verify localhost:5000/hello-world:v1 ```