Docker Image signing with Notation

This article takes a detailed look at image signatures created by Notation, which is one of several tools to create and verify Docker images.

Docker Image signing and attestation series

This article is part of a multi-part series:

Introduction

Notation (formerly known as “Notary V2”) is one of the CLI tools under the Notary Project umbrella. Notary Project is a set of specifications and tools to sign and verify container images and other OCI artifacts. Today, the most important outcome of Notary Project that you should know of is Notation and its specification for image signatures. AFAICT, no other projects/tools (other than Notation CLI) create signatures using that specification.

Notation uses a key/certificate-based approach, where Notation generates a self-signed key and stores it in a cloud-based Key Management Service (KMS) – or you generate it using the KMS. Notation supports the KMS of AWS, Azure, and Venafi CodeSign. Notation can store and retrieve the certificates and keys (and use them for signing/verifying) directly from the KMS (at least with some of them). You could also create certificates as local files (see quick start), but then you would have to manually make sure to correctly distribute them to new machines (e.g. an ephemeral CI/CD runner, or a Kubernetes Pod).

Notation can sign (and verify) both regular container images and non-images, that is, arbitrary OCI artifacts. “OCI” is the Open Container Initiative, a working group that defines open standards for image registries (to abstract away from proprietary vendors like Docker). The OCI defined the image registry API endpoints (“distribution spec”) and file formats (“image spec”) that let you use “image registries” as storage for arbitrary (binary) file “artifacts” (that are not Docker images), e.g. SBOMs, vulnerability reports, or Helm charts. If you are unfamiliar with OCI artifacts, please read this excellent introduction.

Signing with Notation

These are the steps to sign a container image with Notation:

  • On a new/fresh machine, you either create a self-signed key and certificate once (for the first time) and store the key somewhere safe, e.g. in a KMS, or you configure Notation to use a previously generated key/certificate from a KMS. In both cases, refer to Notation’s KMS-specific guides (see AWS guide, Azure KeyVault guide, or Venafi CodeSign). The concrete instructions differ between each KMS.
  • You build and push your container image to your registry, using any tool (e.g. “docker build” or kaniko). The build tool returns the SHA256 digest of the pushed image manifest
  • You run “notation sign [--signature-format cose] <image-with-digest>”. Notation creates a signature for the image manifest and pushes the signature as OCI artifact to the same image registry, making it discoverable under the new image tag named “sha256-<image-digest>”. Notation uses  “OCI references” which are explained in the box below. The basic idea is that when you tell Notation to verify an image, Notation can automatically find its corresponding signature(s). You don’t need to tell Notation where to download the signature from, nor do you have to download the signature manually first and provide it as a file (these are steps you traditionally need to do when verifying files with other tools).
    • Note: Notation supports two signature formats. By default, a textual (JSON-based) format is used (JWS), but you can instead use COSE, which is a binary format producing smaller signature file sizes.
    • Since you most likely want to sign in a CI/CD pipeline, there are wrappers for the Notation CLI for Azure DevOps (see here) and GitHub Actions (see here).

To allow Notation to discover existing signatures for a specific image manifest, Notation does not reinvent the wheel. Notation uses OCI references. This is a new feature introduced in the OCI Distribution spec v1.1 (the distribution spec defines the REST API endpoints of a registry). The OCI references concept is explained well by the ORAS docs, see here.

The basic idea is that whenever you upload an OCI artifact (here: the signature), the uploader (here: the notation CLI) includes a “subject” JSON object in the uploaded OCI (JSON) artifact. The subject points to the other OCI artifact that you want to reference (here: the image manifest to be signed). Registries that implement v1.1 offer a new referrers API endpoint (see here) that registry clients like Notation can call, asking the API “Which other artifacts reference <digest>?”.

However, many registries don’t support this referrers API endpoint yet (e.g. Docker Hub doesn’t, as this page explains: “The Docker Hub registry implementation is based on Distribution. Docker Hub implements version 1.0.1 OCI distribution specification”). To deal with this lack of support, the distribution spec defines a fallback: the basic idea is that the client (that is about to upload the OCI artifact) needs to check whether the referrers API endpoint exists. If does not, it must create a helper manifest that emulates the API call (that is, contains the response that a call to the referrers API would have produced), and assign a new tag for that helper manifest, following the referrer tag schema, so the tag is named “sha256-<sha256-digest-of-target>”.

The Notation CLI, by default, always creates this referrers tag, even for registries that do support the new referrers API endpoint. You can set the optional CLI argument --force-referrers-tag=false when calling “notation sign” to change this behavior, such that Notation will only create the new tag as fallback if it’s really necessary.

If you are curious whether your image registry supports the  referrers API, use ORAS to attach an arbitrary artifact (see here). Then, either run “oras discover --distribution-spec v1.1-referrers-api <image@sha256:...>“, which would print “Error: failed to query referrers API: unsupported” if it wasn’t supported. Or check whether a new tag using the referrer tag schema now exists, using any tool you like
(e.g. “oras repos tags <image-ref-without-tag>“).

Let’s examine a concrete example of the created manifests (note: Notation does not alter the manifest of the image it signs).

{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.index.v1+json",
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "artifactType": "application/vnd.cncf.notary.signature",
      "size": 881,
      "digest": "sha256:780bcb6b16ddb628a84d2282433d029f81ca8be8b66c8304de59a148ec68fcbd",
      "annotations": {
        "io.cncf.notary.x509chain.thumbprint#S256": "[\"834446ca5d99386561b749d727e525857f57d9a66744af63fc1cb7c72762e08f\",\"70a39d1d5cf8d5a1ed70bbc5ac56093bad13c5297b37d96b51dd91e8cc6b3b16\",\"c441f330b33ac268745e3c1de70f4ba4c7659134e08425f47bc946ffb4812766\"]",
        "org.opencontainers.image.created": "2025-01-10T10:08:07Z"
      }
    }
  ]
}
Code language: JSON / JSON with Comments (json)
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "config": {
    "mediaType": "application/vnd.cncf.notary.signature",
    "size": 2,
    "digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a"
  },
  "layers": [
    {
      "mediaType": "application/jose+json",
      "size": 7967,
      "digest": "sha256:3219c7882792780036915ee51e53847a2a8d19f497cd4283783bc43cce5fc409"
    }
  ],
  "subject": {
    "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
    "size": 529,
    "digest": "sha256:0b965ffbd6621318b9a97b1d1ccdbc54146c955f801dc7406401e63385c135d4"
  },
  "annotations": {
    "io.cncf.notary.x509chain.thumbprint#S256": "[\"834446ca5d99386561b749d727e525857f57d9a66744af63fc1cb7c72762e08f\",\"70a39d1d5cf8d5a1ed70bbc5ac56093bad13c5297b37d96b51dd91e8cc6b3b16\",\"c441f330b33ac268745e3c1de70f4ba4c7659134e08425f47bc946ffb4812766\"]",
    "org.opencontainers.image.created": "2025-01-10T10:08:07Z"
  }
}
Code language: JSON / JSON with Comments (json)

Note the subject JSON object, as explained in the “OCI references” box above.

{
  "header": {
    "io.cncf.notary.signingAgent": "The Ant Engine 🐜",
    "x5c": [
      "MIIF0zCCA7ugAwIBAgIUPuAFATDoqNEPakj5BzoZxooh8WcwDQYJKoZIhvcNAQEL\nBQAwfjELMAkGA1UEBhMCVVMxFTATBgNVBAoMDFZNd2FyZSwgSW5jLjEjMCEGA1UE\nCwwaVk13YXJlIEFwcGxpY2F0aW9uIENhdGFsb2cxMzAxBgNVBAMMKlZNd2FyZSBB\ncHBsaWNhdGlvbiBDYXRhbG9nIEludGVybWVkaWF0ZSBDQTAeFw0yMzExMDYxNTMx\nMDdaFw00MzExMDIxNTMxMDdaMGoxHzAdBgNVBAMMFmFwcC1jYXRhbG9nLnZtd2Fy\nZS5jb20xCzAJBgNVBAYTAlVTMRUwEwYDVQQKDAxWTXdhcmUsIEluYy4xIzAhBgNV\nBAsMGlZNd2FyZSBBcHBsaWNhdGlvbiBDYXRhbG9nMIICIjANBgkqhkiG9w0BAQEF\nAAOCAg8AMIICCgKCAgEApOBrKzWWb2o6FuR4BF8FOlmxfal+E/KkEo8fupjOv1ol\nz6Q4loL6u0NrU6X+TbacGGmJWUZ/9SYNrUI1shYcrqp2ViILiMR0K83eRxl44xkh\n8laYGGSQWkUqIbL04SaHuOEY8AYz8xlWziqIEFxuP+xBh+tCQuPgJlrEVXUGBRG4\nspZUtGcreXah9sCOuQXcP1rOXoAmdtjxhR1os8S25tfqRJMI5JVHJjQ9ofYzgHUW\nWuMiMJhdf/1jsvKryPCB8st5Qj76zU0G7svoVsIZc8bX1Tshl9yqdjvSSNOwoPjF\nVcnEZaU/6Z5qqm2ivHdHdW1iVGTnzi+k9s9SaBQGF2ZZoGOWJq7oOHyzalTNS2K+\ndrxhbF7fm3uxWptpxXqwi31PsCkrhPezeyQ7U/7iog1gZ79cFZQas15ClvtvtphY\n3jk2KOJw7xtEklL/tjJLMpgN/DXif7kxMAuydVL9O8KC/0QHTN/8GNvSzo/ezZMB\nCLvF8fbD8dcjF/zlFQ4lFa7/dHjly85uMXhqJCluwe9ZMWnGMckfgfF6d+01h8jO\noutJ1PoWKozTWwHTTd4Kw7xXtZdgdJppUhsgFCgUv3V4sXfu31Oj/BtRENeSeeKB\njoz3bZMQfshIr+7kSStSebtMVUh33smk82daDHywnaCIGUDC2b3ifjAfjMwotbUC\nAwEAAaNdMFswCQYDVR0TBAIwADAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFJy6\nuyrKGkJX8nrhGwmwIp8X0Mv1MB8GA1UdIwQYMBaAFO4dCiDOUj0EboaLqqaTEDbI\nv019MA0GCSqGSIb3DQEBCwUAA4ICAQDC2GUeA+ZVkIj8eTYuKMrWdkX52yi4wbIg\nhyI4Zrq5EDpk5UTnO9TlpFQrFiRvp0HTQ5CBYyozfadAvThfl5YhA6Umiml0MZcX\nB8yhG+nwSoxxZIG7vOTmrbM8LthBez5q4zcdPuQTLL9Hb/dyKkjt0JeBSrOny+8r\nXoi0JK418b1Zbwpi9XXkKTL8YD5GfGjvuFhNvi69VkoMVg4dpZcsOz2h8DPrBSN3\nAsf3f8dsbG0ePnAzK8gIyHNsILsV3j1r7opH1KgGPHV3Mjt1wQ9cLlkQEBlMCKFc\nsvAZ8ZJkbmz4AyDx2lHPQ6EdXTd7OjHAFyWUBo1BYvPiKvXxyLRRAM1evOrGy0s3\nCPvrgUqGa9CmprDgeGQTi2vOMblC7hAaolnE/DSTxduNL8pqDZ3kHRlcw3HFe75j\nGcINApQU7PigiTrxK+cjmcKVzla9TUtsD8aHDhIAANryipwjhL7edHyZ6ENu2jnD\nDNQYhoZ351qaW1SBL03KdBRbeUaA4dTAjSXPj3GA+5gpcEsgVL1ethc199+qOqzf\nB46+D8z+NVTz4hzLSQpahGCj+t1FJ2f12DNS7AbCLCZL2sOtJFYJn8fadqKZYvSw\nLUsF1EQU0WCw1a6KatvFJnTcmvx+kFJYQFkYGTiN2RCUps1L7uE2pxNeL8mylgGV\n3bxXr3zq+w==\n\n",
      "MIIGfzCCBGegAwIBAgIUaGghQIqT+Mdo7Yl9Fj/L0Ljx+6owDQYJKoZIhvcNAQEL\nBQAwdjELMAkGA1UEBhMCVVMxFTATBgNVBAoMDFZNd2FyZSwgSW5jLjEjMCEGA1UE\nCwwaVk13YXJlIEFwcGxpY2F0aW9uIENhdGFsb2cxKzApBgNVBAMMIlZNd2FyZSBB\ncHBsaWNhdGlvbiBDYXRhbG9nIFJvb3QgQ0EwHhcNMjMxMTA2MTUzMDQ3WhcNNDMx\nMTAyMTUzMDQ3WjB+MQswCQYDVQQGEwJVUzEVMBMGA1UECgwMVk13YXJlLCBJbmMu\nMSMwIQYDVQQLDBpWTXdhcmUgQXBwbGljYXRpb24gQ2F0YWxvZzEzMDEGA1UEAwwq\nVk13YXJlIEFwcGxpY2F0aW9uIENhdGFsb2cgSW50ZXJtZWRpYXRlIENBMIICIjAN\nBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxGqFF6lDnQHOq42dmdXmqFdVmNqQ\nrfwP4mtBoLul+bu4ncQlEIgnlJaKqQ+AXfb/OEfx9kCJ/y0FCIxyXvAwwMQcEaqP\nkG4jVwr2zVJPqCWDr9ke63m2XztBKGzWbFHEa8LlUlEuoXDxNedLlLFOjkpE2FuO\nL+x254rVu1CzMqGtRZNTlpTaSTIVpzpPIwrrWDaZDvvcGno+XbHaY7p1Tm5MKyZT\nViC5MTTuHYuYjyocVWlZXGtVb9F+Pj4PREYqTfRVUs66m/3SIPTAXDxbXWC+4Jpc\ntJSvs90TpgX23aCvILYBMLRYD3bAJiY5XQtgR5duhT36rZfdjJv5+vue/OBktGgd\nu2G1xsjunUbYzs1Hie9Xi1D2WbSQ+GRzOkF9bnnrisXb2zCCqEzM0eNr01tWd9ig\n4pkhf37HG4v9jrOQn+5ao36nD4Uo+2FCtGMuogyuwMu0xAuvXCmJGMNEZscCWmsG\nXUB0tAhgWlPHi+IqIf694puQVSpV+FH4SdSM09pwDNvMrQtyw2VuQ/4DBPvz4xbB\nqoG1FCB/dBLyS8gxdaYppGAQiWHJgYYquXRYwqDqOOJ+V9CC/7PQiURKEu6ugMU4\nAHKzP0OADlu0qfmhweT721TYAIo4XoEfvZIchzbGuCjZZBHvBtg7BURiwt7O4juY\nUawxnxVoyHBsWg0CAwEAAaOB/DCB+TAdBgNVHQ4EFgQU7h0KIM5SPQRuhouqppMQ\nNsi/TX0wgbMGA1UdIwSBqzCBqIAUDbYXYxtGfuTHgnn9mmmCm8IoGqGheqR4MHYx\nCzAJBgNVBAYTAlVTMRUwEwYDVQQKDAxWTXdhcmUsIEluYy4xIzAhBgNVBAsMGlZN\nd2FyZSBBcHBsaWNhdGlvbiBDYXRhbG9nMSswKQYDVQQDDCJWTXdhcmUgQXBwbGlj\nYXRpb24gQ2F0YWxvZyBSb290IENBghQMFpaEkHraxHFzOhi7UBy7IrPH2DASBgNV\nHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC\nAgEAe4tY8hqCuzkM0Q1bVsFVemQ3pZvRw/QMyLfFLPauzbQK56rBXhLDEHS7ippF\nYwgnuoqU45d0ep1I6Khdsz8VpXviCOLCi9jk9BDQdMUlWBN08x9nJO0c+d6+cgPL\nLqHKP37osteviwW+CC/nQivgMwHITJVxS1QV+q6Kcg3aZ2W5NgyzTSxnXg3aSVCp\nPMArWfuWRrhNvv3KRFxBhzuNMWqNYRj0qUWsRURUlUCX46vAOS0rf6+4z7cSqvgl\nURDbYgAdLhL+slVarLbkEWTENNLGMmfYa4jkdkmtcR6mvLu/D+TvhY5q5iFo3wfF\n2FhVlHywa0KeODCFukMFqe2XMTofDEYmoAWwr50A/NLHUsawrsTv5Q5cy5aURhZQ\nB+l6VZDfDtMvle7PgUhballmntdk+hCptG/7/Mrh+muGHIWfKhVOePJCdT52MdHI\nNj8EOXCdvIaWcw5uwZpmU699r5b15rEOjmY+CnAHbm7irFCR1x1e1knqxHjXe6J3\n2l7CEXspip5P7Kz8CRDlAglF4LprNu8iZblxcotixN2LFWNnRyoqhHk7GPq/vKMt\n8E9AbxZglNkgCNWQgLJoiDIiD77BayiZBsXz5k0gj00mrlta4LxQeuT5lD1Vs7H9\nX9z49MEGSorq4+2iOen+H7audnIvUbJ/yCOaQIjDVt2CVWY=\n\n",
      "MIIGdDCCBFygAwIBAgIUDBaWhJB62sRxczoYu1AcuyKzx9gwDQYJKoZIhvcNAQEL\nBQAwdjELMAkGA1UEBhMCVVMxFTATBgNVBAoMDFZNd2FyZSwgSW5jLjEjMCEGA1UE\nCwwaVk13YXJlIEFwcGxpY2F0aW9uIENhdGFsb2cxKzApBgNVBAMMIlZNd2FyZSBB\ncHBsaWNhdGlvbiBDYXRhbG9nIFJvb3QgQ0EwHhcNMjMxMTA2MTUzMDM0WhcNNDMx\nMTAyMTUzMDM0WjB2MQswCQYDVQQGEwJVUzEVMBMGA1UECgwMVk13YXJlLCBJbmMu\nMSMwIQYDVQQLDBpWTXdhcmUgQXBwbGljYXRpb24gQ2F0YWxvZzErMCkGA1UEAwwi\nVk13YXJlIEFwcGxpY2F0aW9uIENhdGFsb2cgUm9vdCBDQTCCAiIwDQYJKoZIhvcN\nAQEBBQADggIPADCCAgoCggIBAKa8IGkj5z0TDXV0MmHOBpCcl+Prnr+PR1qM44O5\ntJtw0Uniaka3Vttp4E+M5rbKqjd/neWwClaJWT3Fg2HC7vi4G0QhauZiuaob4hBc\n2DSPJd7/x3T+CIvu6CC3gCLcMJCEYE5mBoCFEiDeiqlHHzf4SI2e6RFJtv+dC7Oc\nJj7BgccZvZXHeL4qHQs+zGU/oGyK+Iwn7mHnJp8rmDEHaHTbtXDeTqbxcPPJurDT\ntrAW/HfrohCoRMZuZBBgf9s876XgoNz8b8FIQksA8OOTgLQdgDaqDAql+ddZzsrk\nl7VhFkztpinrynKpiz2FtlNfOaaD6rq3hpvbYMe3LkJdqw9cr64H2qGf1/Lx+SEh\nrxBwCcs1tmD8LfK4X1Io4JBDMmwfwZ70NdNqxmCxp6y03F52tAhr1DjvEPVXmBgL\nqdPdmpjNMFgPcjMniTBUfQczsy7UNDlmIUvEVNUQISP3KYFJFV4UOWZ+Kpdf1UPY\n95r/JPlRgJKVQ973EvUPlDkSAlY476L46C+jpZNUf6qm352Mf/VMhoSvAXKCYEzj\nWCf46x4nVRCXTR+StapUy5Ru5Azeo0/BXxTErtHatvGA8+igHD4Sn98MiHDO7gXt\nG9eBzIFPx3jyOIQPFhwujHR+8jA/Y9Z5k3T5C6VNpVRZGG7kW3p5gYCM5yq9cCyB\ntm7nAgMBAAGjgfkwgfYwHQYDVR0OBBYEFA22F2MbRn7kx4J5/ZppgpvCKBqhMIGz\nBgNVHSMEgaswgaiAFA22F2MbRn7kx4J5/ZppgpvCKBqhoXqkeDB2MQswCQYDVQQG\nEwJVUzEVMBMGA1UECgwMVk13YXJlLCBJbmMuMSMwIQYDVQQLDBpWTXdhcmUgQXBw\nbGljYXRpb24gQ2F0YWxvZzErMCkGA1UEAwwiVk13YXJlIEFwcGxpY2F0aW9uIENh\ndGFsb2cgUm9vdCBDQYIUDBaWhJB62sRxczoYu1AcuyKzx9gwDwYDVR0TAQH/BAUw\nAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAGOdQSsRNipU\ndZIL/K5fqbgjdYwafpgdjF8z1r9yLKWIEuCCiQFqRZ1CzjnP4jnIlYJXqvqpwklA\nAE56ZNvjo4LzOkElA4emEa+GmLSQ4CqXn+iwX1DYwkyVP7rgZ+k8kjSFjIF2rDhz\ndqnqHA1eyUyb3PhmDFY2694bhWv7D76MzGKLZOFBg3ar0khQp5VaI/bHW1nALAAd\npaM7uAQW/6I20McETtON0weCvbTuljuIVGADLOGwQwjsn7kHbrldEr0EIbtdiEPb\n2Ohis50tPyfrtKVKP/gZBsyTHMaiYxkiNacEDB+cdeDi6kH1Vmm3EFSXWX3vs30D\n3A8AnXw6L7YbXk4PnRy2ueIrs6bya5B9PSzbA2+gEzGnWpZsZmo85DmgpulSSOCM\nlzsP/72ikru888yR0Mvf6BgGestpuXfSSNqUYUTcZVwetyMx/1UC1yCapLJN6eu4\n0oPiQGhSv2uyu6070ne4kXkZL+DYQIjIzqUhS+4AFhBM7drKpo/9gWtHrTq4NRI1\nQ5mnf3lzlPxKV8Uyu2LzdwGb7ySFogAH5/1BGwWVbJvuV+GozJ/AzoPGsNE7mRHu\nijySwgpMy1PoslxC6UhAeY6IdzoqS1PPQzinknikc4XvG7GLZUwtTooOyHx/ofQo\nRlcLAokhium7GrRC8aceTPeaZHW1+ewh\n\n"
    ]
  },
  "payload": "eyJ0YXJnZXRBcnRpZmFjdCI6eyJkaWdlc3QiOiJzaGEyNTY6MGI5NjVmZmJkNjYyMTMxOGI5YTk3YjFkMWNjZGJjNTQxNDZjOTU1ZjgwMWRjNzQwNjQwMWU2MzM4NWMxMzVkNCIsIm1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuZGlzdHJpYnV0aW9uLm1hbmlmZXN0Lmxpc3QudjIranNvbiIsInNpemUiOjUyOX19Cg",
  "protected": "eyJjdHkiOiJhcHBsaWNhdGlvbi92bmQuY25jZi5ub3RhcnkucGF5bG9hZC52MStqc29uIiwiY3JpdCI6WyJpby5jbmNmLm5vdGFyeS5zaWduaW5nU2NoZW1lIl0sImlvLmNuY2Yubm90YXJ5LnNpZ25pbmdUaW1lIjoiMjAyNS0wMS0xMFQxMDowODowN1oiLCJhbGciOiJQUzUxMiIsImlvLmNuY2Yubm90YXJ5LnNpZ25pbmdTY2hlbWUiOiJub3RhcnkueDUwOSJ9",
  "signature": "DdKT47TS4ylznyMj7d3sRLABoytEjCGvhaimQJ1MQBM-tEP5wpR1HMEelCSgCttn0G8TLx5dPqDXMlFpIiapPePHqaHRwUD2LknK0HPqkWG0d2ZKjUdT6xakhkYaPSLeCmipsXtvqMu2Q-JeLRX439SBNrNmY-l7ehckdPonVxBNflzAD-iMh-isyg62QLFM8rG4CsLef6HWq5ULEIYEP-AMTMnHby5SKahOTp8LEE0MRuI86aZJlCuCJ6sXWVri4j47Dl0XtpsXlWl-atN32NiwAvf0f-EV96ScRidkjqwONGNx-ehsE4W0fXDifPkiSQP1cj0Qb1qhI84ZNvEe3N64aPjlGrhA6HaA7Wv9qNTSKYDZpDvCwvhDSb1pKJF6Gd0uI3ncimcM2ywZQrR7niJT7kxkni9WixXsG-pQHN6kazjNAXprqgMbFNA0hErNQRHdgBJ49SJ65sRs1u86Se4tAsZPOb1YLiKyqDkPDX-vbqxMsiMJYwDYYQ4hEEvRL67zCkBgVe8RArAXtv-CXOphMGYAw3wJEppg5w0QpqnEd45lUlaOizI00v8teW0zDhoKJb1xCGjALMyIEwPx8zXUX9EYLscV3EaZgCEACbaLvQI8zdNQQKmXd7kwyS9cvcUZorHhtxqxaeftSO9zFv065W4XdEIZ7XMkHo8p4PU"
}Code language: JSON / JSON with Comments (json)

The payload is just a base64-encoded reference pointing to the digest of the signed image.
signature is, obviously the signature itself.
x5c contains the signing certificate (chain).

Automated verification

To automatically verify image signatures, you have the following options:

  • A Kubernetes operator, configured to reject deploying images that are not signed (or signed with unknown certificates). Each solution uses a different syntax or approach to define the “trust policy”, which specifies which signing certificate(s) you trust:
  • Configure Harbor (see docs) to refuse pulls of unsigned images. Unfortunately, you cannot configure a trust policy in Harbor, such that you cannot configure the specific signing identities you deem trustworthy. This makes the approach rather useless.
  • Verification in your deployment pipeline, e.g. using the wrappers for Azure DevOps (see here) or GitHub Actions (see here). Here, you also need to define a trust policy.

See also the adoptions documentation page for a few more options.

Conclusion

Notation never took off on a larger scale for open-source projects. One exception is Bitnami, who sign their images with Notation, see here. However, Notation can be a good fit for signing and verifying your (closed-source) images in an enterprise/corporate setting. Here, the most viable alternative, Cosign keyless signing, would either force you to use the public Rekor instance (publishing build details to the whole world) or require hosting a private Rekor instance.

Even though Notation requires you to take care of handling certificates and private signing keys, this handling is much simpler than other solutions, such as Docker Content Trust.

Leave a Comment