RSS

Signing and Verifying of images in Harbor with Notation

As container images and cloud native artifacts become common deployment units, users want to make sure that they are authentic in their environments.

From the software producer’s perspective, signing a software artifact enables their consumers to detect tampering and ensure authenticity of the artifact. Signing software can also increase trust when distributing software artifacts to consumers. From the software consumer’s perspective, verifying the signature of a signed artifact ensures its integrity and authenticity.

This article provides a step-by-step guide on signing and verifying an image within the Harbor registry using Notation. Signed images are allowed to be deployed to Kubernetes.

e2e workflow

What is Harbor

Harbor is a registry that allows users to store and manage container images. It is open-source and self-hosted. It provides helpful features such as actively scanning images for vulnerabilities and alerting users of potential risks in real time. Harbor integrates content trust solutions, such as Notation, to help you sign images and verify that the images’ signature comes from a trusted source.

What is Notation

Notation is a standard-based tool and library for signing and verifying OCI artifacts. It generates signatures and associates them with OCI artifacts to ensure integrity for the supply chain. To use notation to sign and verify images we must first have it installed and configured.

This article will guide you through the following key processes:

  • Setting up SSL certificate for HTTPS access to Harbor
  • Installing and Configuring Harbor
  • Installing Notation CLI
  • Generating a Test Key and Self-Signed Certificate
  • Signing of an image in Harbor using Notation
  • Verifying image authenticity within the Harbor registry using Notation.

Prerequisites:

To follow this tutorial, you’ll need the following:

Install Harbor and configure domain name

Harbor supports configuring http and https domain. For security consideration, we use https domain name in this article.

  • Prepare a registered domain name. myharbor-registry.online will be used as the domain name in this tutorial.

  • Point a DNS record to the IPV4 address of your Harbor server.

Installing Certbot

To enable secure HTTPS access to our Harbor registry, we need to obtain an SSL certificate from a Certificate Authority. Certbot will be used to obtain an SSL Certificate from Let’s Encrypt.

Use apt or snap to install certbot.

sudo apt install --classic certbot
sudo certbot certonly --standalone -d myharbor-registry.online

After Certbot successfully obtains a certificate for your domain, it will provide the file paths where the certificate and key files are stored.

certbot

Please take note of these paths, as they will be required in a subsequent step.

Download Harbor

There are two ways you can install Harbor: Installation with Docker and Docker-Compose or with Helm on Kubernetes. In this tutorial, we are going to use Docker and docker-compose to install Harbor on an Ubuntu instance. For a guide on installing Harbor using Helm, please refer to the official documentation.

Download Harbor release package and extract it using the following commands:

wget https://github.com/goharbor/harbor/releases/download/v2.9.1/harbor-online-installer-v2.9.1.tgz
tar -xvf harbor-online-installer-v2.9.1.tgz
cd harbor
cp harbor.yml.tmpl harbor.yml

Configure Harbor domain

In the next step, update the harbor.yml file by setting the hostname to your domain name like in the example below:

hostname: myharbor-registry.online

Replace myharbor-registry.online with the domain name obtained from your domain registrar.

Next, under https update the path of cert and key files to where the certificate and key files are stored. For Example:

Harbor configuration

Run the Installation Script

Execute the Harbor installation script:

sudo ./install.sh

When successful, you should see a similar message like below:

harbor installation script

Log in to Harbor

Finally, log in to Harbor using the following Docker command:

docker login -u admin -p Harbor12345 myharbor-registry.online

Replace myharbor-registry.online with your domain’s address and navigate to https://myharbor-registry.online in your browser to access the Harbor login page, then login using the default Harbor credentials.

Harbor registry dashboard

Install Notation CLI

Install the latest version on Linux. Follow the installation guide for other platforms.

brew install notation

Or for x86_64 processors:

export NOTATION_VERSION=1.0.1
curl -LO https://github.com/notaryproject/notation/releases/download/v$NOTATION_VERSION/notation_$NOTATION_VERSION\_linux_amd64.tar.gz
curl -LO https://github.com/notaryproject/notation/releases/download/v$NOTATION_VERSION/notation_$NOTATION_VERSION\_checksums.txt
shasum --check notation_$NOTATION_VERSION\_checksums.txt

sudo tar xvzf notation_1.0.1_linux_amd64.tar.gz -C /usr/bin/

Build and push an image to Harbor Registry

Before pushing an image to Harbor, create a new project on Harbor to store the image. Harbor organizes images into projects and you can set the visibility to either private or public. By default, there is a library project in Harbor. We will create a new project called notation-project for this tutorial.

Next, build and push the wabbit-networks/net-monitor container image to Harbor with the following commands:

docker build -t myharbor-registry.online/notation-project/net-monitor:v1 https://github.com/wabbit-networks/net-monitor.git#main

docker login myharbor-registry.online

docker push myharbor-registry.online/notation-project/net-monitor:v1

Harbor dashboard

Click on the pushed image: notation-project/net-monitor the “Signed” section has a red mark indicating that the artifact is unsigned.

harbor project page

Create an environment variable for the image digest

After pushing the image, record the image’s digest from the output and use it to set an environment variable for easy referencing of the image.

For example:

export IMAGE=myharbor-registry.online/notation-project/net-monitor@sha256:002c4cbeffe0579eaa87a6bf4b64d554db32e6857098164ed3e03398262310f1

Generating 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.

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

Confirm that the signing key is correctly configured and certificate is stored in the trust store using the following commands:

notation key ls
notation cert ls

Configure environment variables to authenticate to Harbor registry

Set the NOTATION_USERNAME and NOTATION_PASSWORD environment variables to authenticate to Harbor registry.

export NOTATION_USERNAME="YOUR_REGISTRY_USERNAME"
export NOTATION_PASSWORD="YOUR_REGISTRY_PASSWORD"

Learn more about authenticating with OCI-compliant registries in this documentation

Sign the image

Use notation sign command to sign the container image:

notation sign $IMAGE

Once the image is successfully signed, the signed status is updated to a green tick and corresponding signature has been pushed to the registry.

signed image in Harbor registry

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

Verify the image

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

notation verify  $IMAGE

Notation verified image

You can also check the signature digest and inspect the signature and its certificate information to make sure the image is produced by a trusted identity.

notation inspect $IMAGE

Conclusion

In conclusion, this article demonstrated how to set up SSL certificate to allow HTTPS access to Harbor registry. You’ve also learned to install Notation, set up a test key, and generate a self-signed certificate.

The article walked you through the processes of signing and verifying images within the Harbor registry, ensuring the image integrity and authenticity in the software supply chain.