Overview

Container image signing on Red Hat Enterprise Linux (RHEL) systems provides a means of:

  • Validating where a container image came from,

  • Checking that the image has not been tampered with, and

  • Setting policies to determine which validated images can be pulled to a host.

For a more complete understanding of the architecture of container image signing on RHEL systems, see the Container Image Signing Integration Guide.

The OpenShift Container Registry allows the ability to store signatures via REST API. The oc CLI can be used to verify image signatures, with their validiated displayed in the web console or CLI.

Initial support for storing image signatures was added in OpenShift Container Platform 3.3.

Signing Images Using Atomic CLI

OpenShift Container Platform does not automate image signing. Signing requires a developer’s private GPG key, typically stored securely on a workstation. This document describes that workflow.

The atomic command line interface (CLI), version 1.12.5 or greater, provides commands for signing container images, which can be pushed to an OpenShift Container Registry. The atomic CLI is available on Red Hat-based distributions: RHEL, Centos, and Fedora.

You can sign an image at push time:

$ atomic push [--sign-by ...] <image>

Or you can sign an image that has already been pushed to the registry:

$ atomic sign [--sign-by ...] <image>

For full details on how to set up and perform image signing using the atomic CLI, see the RHEL Atomic Host Managing Containers: Signing Container Images documentation.

A specific example workflow of working with the atomic CLI and an OpenShift Container Registry is documented in the Container Image Signing Integration Guide.

Accessing Image Signatures Using Registry API

The OpenShift Container Registry provides an extensions endpoint that allows you to write and read image signatures. The image signatures are stored in the OpenShift Container Platform key-value store via the Docker Registry API.

This endpoint is experimental and not supported by the upstream Docker Registry project. See the upstream API documentation for general information about the Docker Registry API.

Writing Image Signatures

In order to add a new signature to the image, you can use the HTTP PUT method to send a JSON payload to the extensions endpoint:

PUT /extensions/v2/<namespace>/<name>/signatures/<digest>
$ curl -X PUT --data @signature.json http://<user>:<token>@<registry_endpoint>:5000/extensions/v2/<namespace>/<name>/signatures/sha256:<digest>

The JSON payload with the signature content should have the following structure:

{
  "version": 2,
  "type":    "atomic",
  "name":    "sha256:4028782c08eae4a8c9a28bf661c0a8d1c2fc8e19dbaae2b018b21011197e1484@cddeb7006d914716e2728000746a0b23",
  "content": "<cryptographic_signature>"
}

The name field contains the name of the image signature, which must be unique and in the format <digest>@<name>. The <digest> represents an image name and the <name> is the name of the signature. The signature name must be 32 characters long. The <cryptographic_signature> must follow the specification documented in the containers/image library.

In order to attach the signature to the image, the user must have the system:image-signer cluster role. Cluster administrators can add this using:

$ oc adm policy add-cluster-role-to-user system:image-signer <user_name>

Reading Image Signatures

Assuming a signed image has already been pushed into the OpenShift Container Registry, you can read the signatures using the following command:

GET /extensions/v2/<namespace>/<name>/signatures/<digest>
$ curl http://<user>:<token>@<registry_endpoint>:5000/extensions/v2/<namespace>/<name>/signatures/sha256:<digest>

The <namespace> represents the OpenShift Container Platform project name or registry repository name and the <name> refers to the name of the image repository. The digest represents the SHA-256 checksum of the image.

If the given image contains the signature data, the output of the command above should produce following JSON response:

{
  "signatures": [
  {
    "version": 2,
    "type":    "atomic",
    "name":    "sha256:4028782c08eae4a8c9a28bf661c0a8d1c2fc8e19dbaae2b018b21011197e1484@cddeb7006d914716e2728000746a0b23",
    "content": "<cryptographic_signature>"
  }
  ]
}

The name field contains the name of the image signature, which must be unique and in the format <digest>@<name>. The <digest> represents an image name and the <name> is the name of the signature. The signature name must be 32 characters long. The <cryptographic_signature> must follow the specification documented in the containers/image library.

Verifying Image Signatures Using OpenShift CLI

You can verify the signatures of an image imported to an OpenShift Container Registry using the oc adm verify-image-signature command. This command verifies if the image identity contained in the image signature can be trusted by using the public GPG key to verify the signature itself then match the provided expected identity with the identity (the pull spec) of the given image.

By default, this command uses the public GPG keyring located in $GNUPGHOME/pubring.gpg, typically in path ~/.gnupg. By default, this command does not save the result of the verification back to the image object. To do so, you must specify the --save flag.

To modify the image signature verification status, your account must have to have permissions to edit image objects, for example using the image-auditor role.

Using the --save flag on already verified image together with invalid GPG key or invalid expected identity causes the saved verification status to be removed, and the image will become unverified.

To verify an image signature:

$ oc adm verify-image-signature <image> --expected-identity=<pull_spec> [--save] [options]