.. _verify-images: Configure client signature verification policy ============================================== In order to verify container images consumed from Pulp Container Registry the following files need to be configured on the client side: * ``/etc/containers/registries.d/default.yaml`` This is a default registries.d configuration file. You may add to this file or create additional files in registries.d/. For full details and spec refer to https://github.com/containers/image/blob/main/docs/containers-registries.d.5.md Provide a read and write location for a separate ``sigstore`` for the registry in question. Pulp Container Registry has an integrated signature store, therefore there is no need to provide any updates to this file. The client will try to use the registry extentions API to read and write image signatures. * ``/etc/containers/policy.json`` This is a default signature verification policy file that is used to specify the policy, e.g. trusted keys, applicable when deciding whether to accept an image, or individual signatures of that image, as valid. Parsing this json file is performed in a strict manner: unrecognized, duplicated or otherwise invalid fields cause the entire file, and usually the entire operation, to be rejected. For full details and spec refer to https://github.com/containers/image/blob/main/docs/containers-policy.json.5.md Common use cases ================ Verify images mirrored with its original signature into Pulp Container Registry ------------------------------------------------------------------------------- Use case: Pulp Container Registy contains mirrored container images and their signatures from a remote registry. Given that there is already a container repo created, create a remote and specify the url to sync container images from and sigstore url to fetch and store locally their corresponding original signatures. :: $ http POST https://fluffy.example.com/pulp/api/v3/remotes/container/container/ name=legacy-registry-rh url=https://registry.access.redhat.com upstream_name=ubi8/ubi-micro sigstore=https://access.redhat.com/webassets/docker/content/sigstore include_tags:=[\"8.5\"] HTTP/1.1 201 Created Access-Control-Expose-Headers: Correlation-ID Allow: GET, POST, HEAD, OPTIONS Connection: keep-alive Content-Length: 697 Content-Type: application/json Correlation-ID: f488df2618814ba3a8a073c433bdf642 Date: Thu, 10 Mar 2022 15:06:02 GMT Location: /pulp/api/v3/remotes/container/container/64da87b6-7bff-4ab5-9b35-7922e3efd352/ Referrer-Policy: same-origin Server: nginx/1.20.1 Strict-Transport-Security: max-age=15768000 Vary: Accept, Cookie X-Content-Type-Options: nosniff X-Frame-Options: DENY { "ca_cert": null, "client_cert": null, "connect_timeout": null, "download_concurrency": null, "exclude_tags": null, "headers": null, "include_tags": [ "8.5" ], "max_retries": null, "name": "legacy-registry-rh", "policy": "immediate", "proxy_url": null, "pulp_created": "2022-03-10T15:06:02.107728Z", "pulp_href": "/pulp/api/v3/remotes/container/container/64da87b6-7bff-4ab5-9b35-7922e3efd352/", "pulp_labels": {}, "pulp_last_updated": "2022-03-10T15:06:02.107769Z", "rate_limit": null, "sigstore": "https://access.redhat.com/webassets/docker/content/sigstore", "sock_connect_timeout": null, "sock_read_timeout": null, "tls_validation": true, "total_timeout": null, "upstream_name": "ubi8/ubi-micro", "url": "https://registry.access.redhat.com" } Trigger a sync repo task using this remote. .. note:: Some registries have an integrated signature store. In such case there is no need to provide the signature url on the remote. Pulp will automatically discover the integrated signature store capability of the remote registry and will mirror signatures alonside with images. After sync task completion, create distribution with the base_path ``local-ubi8-repo`` under which the image and signatures will be available for pull and verification: :: $ http https://fluffy.example.com/pulp/api/v3/distributions/container/container/1e59e5a8-5247-401d-a9b5-9b3ef07d5efe/ HTTP/1.1 200 OK Access-Control-Expose-Headers: Correlation-ID Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS Connection: keep-alive Content-Length: 659 Content-Type: application/json Correlation-ID: ab2d64376e2849c5bc0cd1f999355115 Date: Thu, 10 Mar 2022 16:08:25 GMT Referrer-Policy: same-origin Server: nginx/1.20.1 Strict-Transport-Security: max-age=15768000 Vary: Accept, Cookie X-Content-Type-Options: nosniff X-Frame-Options: DENY { "base_path": "local-ubi8-repo", "content_guard": "/pulp/api/v3/contentguards/core/content_redirect/27d55db4-2b99-49f6-9838-8ca52647d714/", "description": null, "name": "local-ubi8-repo", "namespace": "/pulp/api/v3/pulp_container/namespaces/fe4d8115-a81c-4eb3-950e-2cf1cc7f033f/", "private": false, "pulp_created": "2022-03-10T16:04:52.026832Z", "pulp_href": "/pulp/api/v3/distributions/container/container/1e59e5a8-5247-401d-a9b5-9b3ef07d5efe/", "pulp_labels": {}, "registry_path": "fluffy.example.com/local-ubi8-repo", "repository": null, "repository_version": "/pulp/api/v3/repositories/container/container/60747422-30d8-4b92-83e6-e6f025b6d829/versions/1/" } Since the original singed identity differs from the location the images are being served, the ``remapIdentity`` and full registry path prefix needs to be specified. :: $ cat /etc/containers/policy.json { "default": [{"type": "reject"}], "transports": { "docker": { "fluffy.example.com/local-ubi8-repo": [ { "type": "signedBy", "keyType": "GPGKeys", "keyPath": "/path-to-rh-key.txt", "signedIdentity": { "type": "remapIdentity", "prefix": "fluffy.example.com/local-ubi8-repo", "signedPrefix": "registry.access.redhat.com/ubi8/ubi-micro" } } ] }, "containers-storage": { "": [{"type": "insecureAcceptAnything"}] /* Allow copy operations on any images stored in containers storage (e.g. podman push) */ } } } podman pull fluffy.example.com/local-ubi8-repo:8.5 Verify images pushed into Pulp Container registry ------------------------------------------------- Use case: Pulp Container Registry serves container images that were pushed into it (signed or not). Push an image into Pulp Container registry and sign it in one go: :: $ podman push fluffy.example.com/myrepo/test-image:foo --sign-by pupsik@redhat.com Copying blob 252fdf0c3b6a done Copying config 829374d342 done Writing manifest to image destination Signing manifest Storing signatures $ podman pull fluffy.example.com/myrepo/test-image:foo Trying to pull fluffy.example.com/myrepo/test-image:foo... Getting image source signatures Checking if image destination supports signatures Copying blob 58147e24f776 skipped: already exists Copying config 829374d342 done Writing manifest to image destination Storing signatures 829374d342ae65a12f3a95911bc04a001894349f70783fda841b1a784008727d $ cat /etc/containers/policy.json { "default": [{"type": "reject"}], "transports": { "docker": { "fluffy.example.com": [ { "type": "signedBy", "keyType": "GPGKeys", "keyPath": "/path-to-pupsik-key.gpg" } ] }, "containers-storage": { "": [{"type": "insecureAcceptAnything"}] /* Allow copy operations on any images stored in containers storage (e.g. podman push) */ } } } Verify images from multiple registries -------------------------------------- Use case: Pull and verify content from Pulp Container registry and also other registries. To pull and verify images coming also from ``registry.access.redhat.com`` create a separate signature store configuration file for it: :: $ cat /etc/containers/registries.d/rh-legacy-registry.yaml docker: registry.access.redhat.com: sigstore: https://access.redhat.com/webassets/docker/content/sigstore $ podman pull registry.access.redhat.com/ubi7/ubi:7.9 Trying to pull registry.access.redhat.com/ubi7/ubi:7.9... Getting image source signatures Checking if image destination supports signatures Copying blob a2745c55c3c1 done Copying blob fd3cd11aea08 done Copying config 873e1c048b done Writing manifest to image destination Storing signatures 873e1c048bf84592ae377f21515961eba5ea20c47223bc890356c680409ef7f1 $ cat /etc/containers/policy.json { "default": [{"type": "reject"}], "transports": { "docker": { "fluffy.example.com/local-ubi8-repo": [ { "type": "signedBy", "keyType": "GPGKeys", "keyPath": "/path-to-rh-key.txt", "signedIdentity": { "type": "remapIdentity", "prefix": "fluffy.example.com/local-ubi8-repo", "signedPrefix": "registry.access.redhat.com/ubi8/ubi-micro" } } ], "fluffy.example.com": [ { "type": "signedBy", "keyType": "GPGKeys", "keyPath": "/path-to-pupsik-key.gpg" } ], "registry.access.redhat.com": [ { "type": "signedBy", "keyType": "GPGKeys", "keyPath": "/path-to-rh-key.txt" } ] }, "containers-storage": { "": [{"type": "insecureAcceptAnything"}] /* Allow copy operations on any images stored in containers storage (e.g. podman push) */ } } }