Quickstart: Sign and validate a container image

Quickly set up a OCI-based registry and use notation to sign and validate a container image

Prerequisites

Before you begin, you need:

Create an OCI-compatible registry

Create and run an OCI-compatible registry on your development computer using the distribution/distribution with the image deletion enabled. The following command creates a registry that is accessible at localhost:5001.

docker run -d -p 5001:5000 -e REGISTRY_STORAGE_DELETE_ENABLED=true --name registry registry

If you want to use Notation with other registries, refer to which registries are compatible with Notary for more alternatives. See Authenticate with OCI-compliant registries when you log in to another OCI registry.

Add an image to the OCI-compatible registry

The following commands build and push the wabbit-networks/net-monitor container image to your container registry.

docker build -t localhost:5001/net-monitor:v1 https://github.com/wabbit-networks/net-monitor.git#main
docker push localhost:5001/net-monitor:v1

Get the digest value of the localhost:5001/net-monitor:v1 image using docker inspect. For example:

docker inspect localhost:5001/net-monitor:v1 -f '{{ .Id }}'
sha256:073b75987e95b89f187a89809f08a32033972bb63cda279db8a9ca16b7ff555a

In the above example, the digest value is sha256:073b75987e95b89f187a89809f08a32033972bb63cda279db8a9ca16b7ff555a. The reference to the container image using the digest value is localhost:5000/net-monitor@sha256:073b75987e95b89f187a89809f08a32033972bb63cda279db8a9ca16b7ff555a.

List the signatures associated with the container image

Use notation ls to show any signatures associated with the container image you built and pushed in the previous section.

IMAGE=localhost:5001/net-monitor@sha256:073b75987e95b89f187a89809f08a32033972bb63cda279db8a9ca16b7ff555a
notation ls $IMAGE

Confirm there are no signatures shown in the output.

Generate a test key and self-signed certificate

Use notation cert generate-test to generate a test RSA key for signing artifacts, and a self-signed X.509 test certificate for verifying artifacts. Please note the self-signed certificate should be used for testing or development purposes only.

The following command generates a test key and a self-signed X.509 certificate. With the --default flag, the test key is set as a default signing key. The self-signed X.509 certificate is added to a named trust store wabbit-networks.io of type ca.

notation cert generate-test --default "wabbit-networks.io"

Use notation key ls to confirm the signing key is correctly configured. Key name with a * prefix is the default key.

notation key ls

Use notation cert ls to confirm the certificate is stored in the trust store.

notation cert ls

Sign the container image

Use notation sign to sign the container image.

notation sign $IMAGE

By default, the signature format is JWS. Use --signature-format to use COSE signature format.

notation sign --signature-format cose $IMAGE

The generated signature is pushed to the registry and the digest of the container image returned.

Use notation ls to show the signature associated with the container image.

notation ls $IMAGE

Confirm there is one signature, for example:

$ notation ls $IMAGE
localhost:5001/net-monitor@sha256:073b75987e95b89f187a89809f08a32033972bb63cda279db8a9ca16b7ff555a
└── application/vnd.cncf.notary.v2.signature
    └── sha256:ba3a68a28648ba18c51a479145fca60d96b43dc96c6ab22f412c89ac56a9038b

Create a trust policy

To verify the container image, configure the trust policy to specify trusted identities that sign the artifacts, and level of signature verification to use. For more details, see trust policy spec.

Create a JSON file with the following trust policy, for example:

cat <<EOF > ./trustpolicy.json
{
    "version": "1.0",
    "trustPolicies": [
        {
            "name": "wabbit-networks-images",
            "registryScopes": [ "*" ],
            "signatureVerification": {
                "level" : "strict" 
            },
            "trustStores": [ "ca:wabbit-networks.io" ],
            "trustedIdentities": [
                "*"
            ]
        }
    ]
}
EOF

Use notation policy import to import the trust policy configuration from a JSON file. For example:

notation policy import ./trustpolicy.json

Use notation policy show to view the applied policy configuration. For example:

notation policy show

The above JSON creates a trust policy named wabbit-networks-images. The policy has registryScopes set to *, which applies the policy to all the artifacts of any registry. The signatureVerification is set to strict, which checks all validations and any failure will fail the signature verification. This policy uses the wabbit-networks.io trust store of type ca which was created in the previous step. For more details on trust policies, see trust policy spec.

To enable trust policy for specific repositories, set the registryScopes to those specific repositories. For example:

"registryScopes": [ 
    "localhost:5001/net-monitor",
    "localhost:5001/nginx",
    "localhost:5001/hello-world"
]

Verify the container image

Use notation verify to verify signatures associated with the container image.

notation verify $IMAGE

The digest of the supplied artifact is returned upon successful verification.

Cleanup

To remove the sample registry running on your development computer:

docker rm -f registry

To reset your notation configuration, remove the notation configuration directory. For more details, see Remove the configuration files.