Edit

Share via


Sign container images by using Notation and Trusted Signing (preview)

This article is part of a series on ensuring the integrity and authenticity of container images and other Open Container Initiative (OCI) artifacts. For the complete picture, start with the overview, which explains why signing matters and outlines the various scenarios.

This article focuses on signing by using Notary Project tooling, Notation, and Trusted Signing:

  • What you'll learn here: How to use the Notation command-line interface (CLI) to sign artifacts by using Trusted Signing.
  • Where it fits: Trusted Signing is an alternative to Azure Key Vault. Although Key Vault gives organizations full control of certificate lifecycle management, Trusted Signing provides streamlined signing experience with zero-touch certificate lifecycle management and short-lived certificates.
  • Why it matters: Trusted Signing simplifies the developer experience while providing strong identity assurance. It helps teams reduce operational complexity without compromising security.

Prerequisites

Before you can sign and verify container images by using Notation and Trusted Signing, you need to set up the required Azure resources and install the necessary tools. This section walks you through preparing Azure Container Registry, configuring Trusted Signing, and setting up the Azure CLI as your development environment.

Note

At this time, Trusted Signing is available only to organizations based in the United States and Canada that have a verifiable history of three years or more.

Prepare container images in Azure Container Registry

  1. Create or use a container registry to store container images, OCI artifacts, and signatures.
  2. Push or use a container image in your container registry.

Set up Trusted Signing

Set up a Trusted Signing account and certificate profile in your Azure subscription.

Your certificate profile must include country/region (C), state or province (ST or S), and organization (O) in the certificate subject. The Notary Project specification requires these fields.

Set up the Azure CLI

Install the Azure CLI, or use Azure Cloud Shell.

Install the Notation CLI and Trusted Signing plug-in

This guide runs commands on Linux AMD64 and Windows as examples.

  1. Install Notation CLI v1.3.2:

    curl -Lo notation.tar.gz https://github.com/notaryproject/notation/releases/download/v1.3.2/notation_1.3.2_linux_amd64.tar.gz
    # Validate the checksum
    EXPECTED_SHA256SUM="e1a0f060308086bf8020b2d31defb7c5348f133ca0dba6a1a7820ef3cbb6dfe5"
    echo "$EXPECTED_SHA256SUM  notation.tar.gz" | sha256sum -c -
    # Continue if sha256sum matches
    tar xvzf notation.tar.gz
    cp ./notation /usr/local/bin
    

    For other platforms, see the Notation installation guide.

  2. Install the Trusted Signing plug-in:

    notation plugin install --url "https://github.com/Azure/trustedsigning-notation-plugin/releases/download/v1.0.0-beta.1/notation-azure-trustedsigning_1.0.0-beta.1_linux_amd64.tar.gz" --sha256sum 538b497be0f0b4c6ced99eceb2be16f1c4b8e3d7c451357a52aeeca6751ccb44
    

    Find the latest plug-in URL and checksum on the release page.

  3. Verify plug-in installation:

    notation plugin ls
    

    Example output:

    NAME                   DESCRIPTION                                            VERSION   CAPABILITIES                ERROR
    azure-trustedsigning   Sign OCI artifacts using the Trusted Signing Service   0.3.0     [SIGNATURE_GENERATOR.RAW]   <nil>
    

Configure environment variables

Set the following environment variables for use in subsequent commands. Replace placeholders with your actual values.

You can find the required values in the Azure portal:

  • For Trusted Signing account information, go to your account, and then select Overview.
  • For certificate profile information, go to your account, and then select Objects > Certificate Profiles.
# Trusted Signing environment variables
TS_SUB_ID="<subscription-id>"
TS_ACCT_RG=<ts-account-resource-group>
TS_ACCT_NAME=<ts-account-name>
TS_ACCT_URL=<ts-account-url>
TS_CERT_PROFILE=<ts-cert-profile>
TS_CERT_SUBJECT=<ts-cert-subject>
TS_SIGNING_ROOT_CERT="https://www.microsoft.com/pkiops/certs/Microsoft%20Enterprise%20Identity%20Verification%20Root%20Certificate%20Authority%202020.crt"
TS_TSA_URL="http://timestamp.acs.microsoft.com/"
TS_TSA_ROOT_CERT="http://www.microsoft.com/pkiops/certs/microsoft%20identity%20verification%20root%20certificate%20authority%202020.crt"

# Azure Container Registry and image environment variables
ACR_SUB_ID="<acr-subscription-id>"
ACR_RG=<acr-resource-group>
ACR_NAME=<registry-name>
ACR_LOGIN_SERVER=$ACR_NAME.azurecr.io
REPOSITORY=<repository>
TAG=<tag>
IMAGE=$ACR_LOGIN_SERVER/${REPOSITORY}:$TAG

Sign in to Azure

Use the Azure CLI to sign in with your user identity:

az login
USER_ID=$(az ad signed-in-user show --query id -o tsv)

Note

This guide demonstrates signing in with a user account. For other identity options, including a managed identity, see Authenticate to Azure by using the Azure CLI.

Assign permissions for Azure Container Registry and Trusted Signing

Grant your identity the necessary roles to access Container Registry:

  • For registries enabled with attribute-based access control (ABAC), assign:
    • Container Registry Repository Reader
    • Container Registry Repository Writer
  • For non-ABAC registries, assign:
    • AcrPull
    • AcrPush
az role assignment create --role "Container Registry Repository Reader" --assignee $USER_ID --scope "/subscriptions/$ACR_SUB_ID/resourceGroups/$ACR_RG/providers/Microsoft.ContainerRegistry/registries/$ACR_NAME"
az role assignment create --role "Container Registry Repository Writer" --assignee $USER_ID --scope "/subscriptions/$ACR_SUB_ID/resourceGroups/$ACR_RG/providers/Microsoft.ContainerRegistry/registries/$ACR_NAME"

Assign the role Trusted Signing Certificate Profile Signer to your identity so that you can sign by using Trusted Signing:

az role assignment create --assignee $USER_ID --role "Trusted Signing Certificate Profile Signer" --scope "/subscriptions/$TS_SUB_ID/resourceGroups/$TS_ACCT_RG/providers/Microsoft.CodeSigning/codeSigningAccounts/$TS_ACCT_NAME/certificateProfiles/$TS_CERT_PROFILE"

Sign a container image

# Authenticate to Azure Container Registry
az acr login --name $ACR_NAME

# Download the timestamping root certificate
curl -o msft-tsa-root-certificate-authority-2020.crt $TS_TSA_ROOT_CERT

# Sign the image
notation sign --signature-format cose --timestamp-url $TS_TSA_URL --timestamp-root-cert "msft-tsa-root-certificate-authority-2020.crt" --id $TS_CERT_PROFILE --plugin azure-trustedsigning --plugin-config accountName=$TS_ACCT_NAME --plugin-config baseUrl=$TS_ACCT_URL --plugin-config certProfile=$TS_CERT_PROFILE $IMAGE

Key flags explained:

  • --signature-format cose: Uses CBOR Object Signing and Encryption (COSE) format for signatures.
  • --timestamp-url: Uses the timestamping server that Trusted Signing supports.
  • --plugin-config: Passes configuration to the Trusted Signing plug-in.

List signed images and signatures:

notation ls $IMAGE

Example output:

myregistry.azurecr.io/myrepo@sha256:5d0bf1e8f5a0c74a4c22d8c0f962a7cfa06a4f9d8423b196e482df8af23b5d55
└── application/vnd.cncf.notary.signature
    └── sha256:d3a4c9fbc17e27b19a0b28e7b6a33f2c0f541dbdf8d2e5e8d0d79a835e8a76f2a

Verify a container image

  1. Download and add root certificates:

    curl -o msft-root-certificate-authority-2020.crt $TS_SIGNING_ROOT_CERT
    SIGNING_TRUST_STORE="myRootCerts"
    notation cert add --type ca --store $SIGNING_TRUST_STORE msft-root-certificate-authority-2020.crt
    
    curl -o msft-tsa-root-certificate-authority-2020.crt $TS_TSA_ROOT_CERT
    TSA_TRUST_STORE="myTsaRootCerts"
    notation cert add -t tsa -s $TSA_TRUST_STORE msft-tsa-root-certificate-authority-2020.crt
    notation cert ls
    

  1. Create a trust policy JSON file:

    cat <<EOF > trustpolicy.json
    {
        "version": "1.0",
        "trustPolicies": [
            {
                "name": "myPolicy",
                "registryScopes": [ "$ACR_LOGIN_SERVER/$REPOSITORY" ],
                "signatureVerification": {
                    "level" : "strict"
                },
                "trustStores": [ "ca:$SIGNING_TRUST_STORE", "tsa:$TSA_TRUST_STORE" ],
                "trustedIdentities": [
                    "x509.subject: $TS_CERT_SUBJECT"
                ]
            }
        ]
    }
    EOF
    

    Import and check the policy:

    notation policy import trustpolicy.json
    notation policy show
    

  1. Verify the image:

    notation verify $IMAGE
    

    Example output:

    Successfully verified signature for myregistry.azurecr.io/myrepo@sha256:5d0bf1e8f5a0c74a4c22d8c0f962a7cfa06a4f9d8423b196e482df8af23b5d55
    

    If verification fails, ensure that your trust policy and certificates are configured correctly.