Lab 7.0 - Container image signing

Return to Workshop

In this lab, you will use podman to sign container images and create trust policies to control access to registries.

To begin the image signing procedure, a signature claim is generated by encrypting a container image manifest using a private gpg key. The signature claims are stored in a file system or web server where they can be decrypted later and used to pull signed images.

Image Encryption

The procedure is reversed when pulling signed images.

Image Decryption

Configuring the signature claim store

On the bastion server, create a configuration for the node1 registry.

Become root to do this.

sudo -i

Create the configuration for node1.

cat <<EOF > /etc/containers/registries.d/node1-0.example.redhatgov.io.yaml
docker:
  node1-0.example.redhatgov.io:5000:
    sigstore: file:///var/tmp/sigstore/node1-0.example.redhatgov.io
    sigstore-staging: file:///var/tmp/sigstore/node1-0.example.redhatgov.io
EOF

Exit from the root shell.

exit

Notice we are using the /var/tmp/sigstore directory to store signature claims. This allows the system administrator to configure the signature store for a given registry and allows rootless users to push and pull signed container images.

Create a directory for the signature claims for the node1 registry.

mkdir -p /usr/tmp/sigstore/node1-0.example.redhatgov.io

Generating key pairs

Generate the gpg key pair. You’ll be prompted to set a pass phrase. Set it to 1234567890 so you don’t forget. :)

gpg2 --quick-gen-key --yes ec2-user

Now export the public key. You’ll need it later.

mkdir /usr/tmp/keys
gpg2 --export ec2-user > /usr/tmp/keys/gpg-pubkey.gpg

Confirm you have a container image with the correct REPOSITORY and TAG as shown.

podman tag registry.fedoraproject.org/fedora:latest node1-0.example.redhatgov.io:5000/fedora:latest
podman images
REPOSITORY                                          TAG      IMAGE ID       CREATED       SIZE
node1-0.example.redhatgov.io:5000/fedora/latest   latest   a4a954bf99ed   2 weeks ago   184 MB

Login to the registry, then sign and push the image. When podman signs the image it will prompt for the gpg key pass phrase you used to create the key pair. It then creates a signature claim.

podman login --username=redhat --password=redhat node1-0.example.redhatgov.io:5000
Login Succeeded!
podman push --sign-by ec2-user node1-0.example.redhatgov.io:5000/fedora/latest
Getting image source signatures
Copying blob acc367faa01d done
Copying blob 2e7173fdd054 done
Copying blob 852626d9f911 done
Copying blob 680fa67a4ae7 done
Copying blob 58e73958f78a done
Copying config a4a954bf99 done
Writing manifest to image destination
Signing manifest
Storing signatures

Confirm the signature claim was created.

tree /var/tmp/sigstore
/var/tmp/sigstore
└── node1-0.example.redhatgov.io
    └── fedora
        └── latest@sha256=f1b2dc7705f263e24b6cc0f925df2593e087bfbca5e36053a2868e0c2a190569
            └── signature-1

2 directories, 1 file

Confirm the push succeeded.

curl  --user redhat:redhat https://node1-0.example.redhatgov.io:5000/v2/_catalog
{"repositories":["fedora/latest"]}

Working with trust policies

In this exercise you will configure the image trust policy so that it allows only signed images to be pulled from a trusted registry on node1.

Start by examining the current trust policy (which accepts anything) then create a default policy that rejects all image pulls.

podman image trust show
default             insecureAcceptAnything

Change the policy to reject by default.

sudo podman image trust set -t reject default
podman image trust show
          insecureAcceptAnything
default   reject

Pulling signed images

Now we are ready to try an image pull. To make certain you are authenticated to the registry, login again.

podman login --username=redhat --password=redhat node1-0.example.redhatgov.io:5000
Login Succeeded!

Now test that image pulls are rejected by default.

podman pull node1-0.example.redhatgov.io:5000/fedora/latest
Trying to pull https://node1-0.example.redhatgov.io:5000/fedora/latest...
  Running image docker://node1-0.example.redhatgov.io:5000/fedora/latest:latest is rejected by policy.
Error: error pulling image "node1-0.example.redhatgov.io:5000/fedora/latest": unable to pull node1-0.example.redhatgov.io:5000/fedora/latest: unable to pull image: Source image rejected: Running image docker://node1-0.example.redhatgov.io:5000/fedora/latest:latest is rejected by policy.

Set a trust policy for node1-0.example.redhatgov.io using your exported public gpg key.

sudo podman image trust set --type signedBy --pubkeysfile /usr/tmp/keys/gpg-pubkey.gpg node1-0.example.redhatgov.io:5000

Now examine the image trust again. It should show that any image pulls from node1-0.example.redhatgov.io must be signed.

podman image trust show
default                      reject
node1-0.example.redhatgov.io:5000   signedBy                 ec2-user   file:///var/tmp/sigstore/node1-0.example.redhatgov.io

Finally, try to pull the image from the trusted registry on node1-0.example.redhatgov.io and it should succeed.

podman pull node1-0.example.redhatgov.io:5000/fedora/latest
Trying to pull node1-0.example.redhatgov.io:5000/fedora/latest...
Getting image source signatures
Checking if image destination supports signatures
Copying blob e9bd946da7a5 skipped: already exists
Copying blob a727de8a9a50 skipped: already exists
Copying blob 60832cdfaf75 skipped: already exists
Copying blob f304768caba3 skipped: already exists
Copying blob 103696e3c551 skipped: already exists
Copying config a4a954bf99 done
Writing manifest to image destination
Storing signatures

Create a trust policy for Red Hat images.

In this exercise, you will create a trust policy that allows only signed images to be pulled from Red Hat’s Container Catalog.

First, try a pull and it should fail because of the default policy.

podman pull registry.access.redhat.com/ubi8/ubi
Trying to pull registry.access.redhat.com/ubi8/ubi...
  Running image docker://registry.access.redhat.com/ubi8/ubi:latest is rejected by policy.
Error: error pulling image "registry.access.redhat.com/ubi8/ubi": unable to pull registry.access.redhat.com/ubi8/ubi: unable to pull image: Source image rejected: Running image docker://registry.access.redhat.com/ubi8/ubi:latest is rejected by policy.

Configure the sigstore for the RedHat registry.

Become root to do this.

sudo -i

Create the configuration for node1.

cat <<EOF > /etc/containers/registries.d/registry.access.redhat.com.yaml
docker:
     registry.access.redhat.com:
         sigstore: https://access.redhat.com/webassets/docker/content/sigstore
EOF

Exit from the root shell.

exit

Configure the trust policy for the RedHat registry.

sudo podman image trust set -f /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release registry.access.redhat.com

Examine the trust policy again.

podman image trust show
default                              reject
registry.access.redhat.com           signedBy                security@redhat.com, security@redhat.com  https://access.redhat.com/webassets/docker/content/sigstore
node1-0.example.redhatgov.io:5000  signedBy                ec2-user                                  file:///var/tmp/sigstore/node1-0.jajcontainer.rhnaps.io
                                     insecureAcceptAnything

Try the image pull again.

podman pull registry.access.redhat.com/ubi8/ubi
Trying to pull registry.access.redhat.com/ubi8/ubi...
Getting image source signatures
Checking if image destination supports signatures
Copying blob 0bb54aa5e977 done
Copying blob 941e1e2b31a8 done
Copying config 0c46e5c7a8 done
Writing manifest to image destination
Storing signatures
0c46e5c7a82a97d21447ee6a1ef0d407317642c9361b562456395e087be08774

This kbase article has more detail.

Blocking a registry

It is recommended that a registry trust policy be used to control which registries you want to allow users to pull and push from. This gives greater flexibility, and supports all container runtimes and tools including the docker daemon, podman, buildah and cri-o.

There are a few ways to approach this:

  • Create a default reject policy and trust only node1

  • Create a default accept policy and reject node2

Take what you’ve learned and give each a try.

Now try to pull the image from node2-0.example.redhatgov.io, it should fail.

podman pull node2-0.example.redhatgov.io:5000/fedora/latest
Trying to pull https://node2-0.example.redhatgov.io:5000/fedora/latest...
  Running image docker://node2-0.example.redhatgov.io:5000/fedora/latest:latest is rejected by policy.
Error: error pulling image "node2-0.example.redhatgov.io:5000/fedora/latest": unable to pull node2-0.example.redhatgov.io:5000/fedora/latest: unable to pull image: Source image rejected: Running image docker://node2-0.example.redhatgov.io:5000/fedora/latest:latest is rejected by policy.

Workshop Details

Domain Red Hat Logo
Workshop
Student ID

Return to Workshop