Skip to main content
Redhat Developers  Logo
  • Products

    Platforms

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat AI
      Red Hat AI
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • View All Red Hat Products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat Developer Hub
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat OpenShift Local
    • Red Hat Developer Sandbox

      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Openshift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer Productivity

      • Developer productivity
      • Developer Tools
      • GitOps
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Secure Development & Architectures

      • Security
      • Secure coding
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • Product Documentation
    • API Catalog
    • Legacy Documentation
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

How to verify container signatures in disconnected OpenShift

August 27, 2025
Mohammad Ahmad Tom Stockwell Alex Guidi Jack Adolph
Related topics:
ContainersDisconnected EnvironmentsKubernetesOpen sourceSecurity
Related products:
Red Hat OpenShiftRed Hat OpenShift Container Platform

Share:

    The introduction of sigstore and its suite of tools, such as CoSign, has simplified the signing and verification of container images. Red Hat OpenShift Container Platform 4.19 leverages the oc-mirror v2 tool to enable the mirroring of container images and their cryptographic signatures to local/remote registries. This development is significant as it facilitates container signature verification with CoSign in disconnected, or "air-gapped" environments.

    This article presents a proof of concept outlining the steps required to mirror content for a disconnected OpenShift installation. It further details how to enable and test signature verification using CoSign within this setup.

    This article covers: 

    • A proof of concept for a feature that is in technology preview at the time of this writing.
    • A procedure tested in a home lab environment using a single node OpenShift instance.
    • The oc-mirror client used for this procedure was version 4.19.5, which was the latest version available at the time of writing.
    • This procedure was tested with the Red Hat Operators catalog, as it is currently the only one that provides signatures for all of its operator images.
    • The exact code used to create this demo and produce the results. 

    While we hope these steps will work for others, platform differences may produce different results. This is not a production-ready guide, nor is it exhaustive or comprehensive.

    Mirroring signatures with oc-mirror 

    This section details the configuration of the ImageSetConfiguration file. This file specifies which container images and operator catalogs to mirror from a connected registry to your disconnected environment.

    # cat v2_imageset-config_with_RHOperators_4.19.yml
    kind: ImageSetConfiguration
    apiVersion: mirror.openshift.io/v2alpha1
    archiveSize: 16
    mirror:
      platform:
        channels:
        - name: stable-4.19
          minVersion: 4.19.5
          maxVersion: 4.19.5
      operators:
      - catalog: registry.redhat.io/redhat/redhat-operator-index:v4.19
        full: false
        packages:
          - name: advanced-cluster-management
          - name: ansible-automation-platform-operator
          - name: datagrid
          - name: lvms-operator
          - name: mcg-operator
          - name: ocs-client-operator
          - name: ocs-operator
          - name: odf-csi-addons-operator
          - name: odf-multicluster-orchestrator
          - name: odf-operator
          - name: odr-cluster-operator
          - name: openshift-gitops-operator
          - name: quay-operator
          - name: rhbk-operator
          - name: rhsso-operator
          - name: servicemeshoperator
          - name: servicemeshoperator3
          - name: skupper-operator
          - name: submariner
      additionalImages:
       - name: registry.redhat.io/ubi8/ubi:latest
       - name: registry.redhat.io/ubi9/ubi:latest

    Run like this:

    oc-mirror --v2 --image-timeout 20m0s --retry-times 5 --retry-delay 5s --remove-signatures=false -c  v2_imageset-config_all_RHOperators_4.19.yml --workspace file:///data/oc-mirror/workdir/  --log-level info docker://quay.local.momolab.io:443/mirror

    Apply configuration changes to OpenShift 

    First, add the Signature Verification FeatureGate. To do this, edit the FeatureGate object to ensure its spec contains the following configuration:

    Note that TechPreviewNoUpgrade will prevent updates of the cluster and cannot be reversed.

    $ export EDITOR=vi
    $ oc edit featuregate cluster
    spec: 
      featureSet: TechPreviewNoUpgrade

    This enables the required SigstoreImageVerification feature. This change will trigger an update to the machine configuration. You can monitor the progress with the following command.

    Wait for OpenShift to apply the new policies.

    This may take up to 10 minutes, and the API might become unavailable (as it is single node OpenShift).

    $  oc get mcp
    NAME     CONFIG                                             UPDATED   UPDATING   DEGRADED   MACHINECOUNT   READYMACHINECOUNT   UPDATEDMACHINECOUNT   DEGRADEDMACHINECOUNT   AGE
    master   rendered-master-1c612127e5ae4fd194b9ecac38fe4f9d   True      False      False      1              1                   1                     0                      13d
    worker   rendered-worker-c88af97175298b6ed0d4f17ce32c9852   True      False      False      0              0                   0                     0                      13d
    

    Wait for the UPDATING column to transition from False -> True -> False.

    A good way to check if the process has completed is to confirm that the ClusterImagePolicies CRD is available.

    $ oc get crds |grep -i clusterimagepolicies
    clusterimagepolicies.config.openshift.io                          2025-08-03T23:26:20Z

    Once the oc-mirror process is complete, you should see this:

    # ls -la /data/oc-mirror/workdir/working-dir/cluster-resources/
    total 28
    drwxr-xr-x.  2 root root 4096 Aug  2 10:04 .
    drwxr-xr-x. 10 root root  158 Aug  2 06:53 ..
    -rw-r--r--.  1 root root  431 Aug  2 10:04 cc-redhat-operator-index-v4-19.yaml
    -rw-r--r--.  1 root root  433 Aug  2 10:04 cs-redhat-operator-index-v4-19.yaml
    -rw-r--r--.  1 root root 3113 Aug  2 10:04 idms-oc-mirror.yaml
    -rw-r--r--.  1 root root  929 Aug  2 10:04 itms-oc-mirror.yaml
    -rw-r--r--.  1 root root 1626 Aug  2 10:04 signature-configmap.json
    -rw-r--r--.  1 root root 1614 Aug  2 10:04 signature-configmap.yaml

    In the cc-redhat-operator-index-v4-19.yaml and cs-redhat-operator-index-v4-19.yaml files, replace the metadata name with redhat-operators, as some operators use this CatalogSource name and will fail otherwise.

    Generate ClusterImagePolicy for each repository (generates remapIdentity).

    The following script has been provided to generate a ClusterImagePolicy for each repository mirrored to the local mirror.

    # cat generate_cluster_image_policies.py
    
    # looks up files generated by oc-mirror v2, and creates a ClusterImagePolicy for each mirror/source pair.
    # Run using python generate_cluster_image_policies.py
    import os
    import yaml
    
    # Directory where oc-mirror YAML files are stored
    input_dir = "files/disconnected/4.18/" # Change to match what you need.
    output_file = "ClusterImagePolicies.yaml"
    
    # Red Hat public key: security.access.redhat.com/data/63405576.txt (between BEGIN and END, passed through | base64 -w0) 
    sigstore_key = """LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQ0lqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUEwQVN5dUgyVExXdkJVcVBIWjRJcAo3NWc3RW5jQmtnUUhkSm5qenhBVzVLUVRNaC9zaUJvQi9Cb1NydGlQTXduQ2hiVENuUU9JUWVadURpRm5odUo3Ck0vRDNiN0pvWDBtMTIzTmNDU242N21BZGpCYTZCZzZrdWtaZ0NQNFpVWmVFU2FqV1gvRWp5bEZjUkZPWFc1N3AKUkRDRU40MkovallsVnF0K2c5K0dya2VyOFN6ODZIM2wwdGJxT2RqYnovVnhIWWh3RjBjdFVNSHN5VlJEcTJRUAp0cXpOWGxtbE1oUy9Qb0ZyNlI0dS83SENuL0srTGVnY08yZkFGT2I0MEt2S1NLS1ZENmxld1VaRXJob3AxQ2dKClhqRHRHbW1POWRHTUY3MW1mNkhFZmFLU2R5K0VFNmlTRjJBMlZ2OVFoQmF3TWlxMmtPekVpTGc0bkFkSlQ4d2cKWnJNQW1QQ3FHSXNYTkdaNC9RK1lUd3dsY2UzZ2xxYjVMOXRmTm96RWRTUjlOODVERVNmUUxRRWRZM0NhbHdLTQpCVDFPRWhFWDF3SFJDVTRkck1PZWo2Qk5XMFZ0c2NHdEhtQ3JzNzRqUGV6aHdOVDh5cGt5UytUMHpUNFRzeTZmClZYa0o4WVNIeWVuU3pNQjJPcDJidnNFM2dyWStzNzRXaEc5VUlBNkRCeGNUaWUxNU5Tekt3Znphb05XT0RjTEYKcDdCWThhYUhFMk1xRnhZRlgrSWJqcGtRUmZhZVFRc291REZkQ2tYRUZWZlBwYkQyZGs2RmxlYU1UUHV5eHRJVApnalZFdEdRSzJxR0NGR2lRSEZkNGhmVitlQ0E2M0pybzF6MHpvQk01QmJJSVEzK2VWRnd0M0FsWnA1VVZ3cjZkCnNlY3FraS95cm12M1kwZHFaOVZPbjNVQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ=="""
    
    # Collect mirror-source pairs
    pairs = []
    
    for fname in os.listdir(input_dir):
        if fname.endswith("oc-mirror.yaml"):
            with open(os.path.join(input_dir, fname)) as f:
                docs = list(yaml.safe_load_all(f))
                for doc in docs:
                    if not doc or "spec" not in doc:
                        continue
                    key = "imageDigestMirrors" if "imageDigestMirrors" in doc["spec"] else "imageTagMirrors"
                    for entry in doc["spec"].get(key, []):
                        source = entry["source"]
                        for mirror in entry["mirrors"]:
                            pairs.append((mirror, source))
    
    # Deduplicate
    unique_pairs = sorted(set(pairs))
    
    # Generate policy YAMLs
    policies = []
    for mirror, source in unique_pairs:
        name = mirror.split("/")[-1].replace(".", "-").replace(":", "-")
        policy = {
            "apiVersion": "config.openshift.io/v1alpha1",
            "kind": "ClusterImagePolicy",
            "metadata": {"name": f"enforce-signatures-quay-mirror-{name}"},
            "spec": {
                "scopes": [mirror],
                "policy": {
                    "type": "sigstore",
                    "rootOfTrust": {
                        "policyType": "PublicKey",
                        "publicKey": {
                            "keyData": sigstore_key
                        }
                    },
                    "signedIdentity": {
                        "type": "RemapIdentity",
                        "matchPolicy": "RemapIdentity",
                        "remapIdentity": {
                            "prefix": mirror,
                            "signedPrefix": source
                        }
                    }    
                }
            }
        }
        policies.append(policy)
    
    # Output to file
    with open(output_file, "w") as f:
         f.write("# This was generated by https://github.com/momoah/snolibvirt/blob/main/files/generate_cluster_image_policies.py\n")
        f.write("---\n" + "\n---\n".join(yaml.dump(p, sort_keys=False) for p in policies))
    
    print(f"Generated {len(policies)} ClusterImagePolicy objects in {output_file}")
    

    Refer to the source on GitHub.

    This is what the generated ClusterImagePolicy YAML for OpenShift release images looks like:

    ---
    apiVersion: config.openshift.io/v1alpha1
    kind: ClusterImagePolicy
    metadata:
     name: enforce-signatures-quay-mirror-release-images
    spec:
     scopes:
     - quay.local.momolab.io:443/mirror/openshift/release-images
     policy:
       type: sigstore
       rootOfTrust:
         policyType: PublicKey
         publicKey:
           keyData: LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQ0lqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUEwQVN5dUgyVExXdkJVcVBIWjRJcAo3NWc3RW5jQmtnUUhkSm5qenhBVzVLUVRNaC9zaUJvQi9Cb1NydGlQTXduQ2hiVENuUU9JUWVadURpRm5odUo3Ck0vRDNiN0pvWDBtMTIzTmNDU242N21BZGpCYTZCZzZrdWtaZ0NQNFpVWmVFU2FqV1gvRWp5bEZjUkZPWFc1N3AKUkRDRU40MkovallsVnF0K2c5K0dya2VyOFN6ODZIM2wwdGJxT2RqYnovVnhIWWh3RjBjdFVNSHN5VlJEcTJRUAp0cXpOWGxtbE1oUy9Qb0ZyNlI0dS83SENuL0srTGVnY08yZkFGT2I0MEt2S1NLS1ZENmxld1VaRXJob3AxQ2dKClhqRHRHbW1POWRHTUY3MW1mNkhFZmFLU2R5K0VFNmlTRjJBMlZ2OVFoQmF3TWlxMmtPekVpTGc0bkFkSlQ4d2cKWnJNQW1QQ3FHSXNYTkdaNC9RK1lUd3dsY2UzZ2xxYjVMOXRmTm96RWRTUjlOODVERVNmUUxRRWRZM0NhbHdLTQpCVDFPRWhFWDF3SFJDVTRkck1PZWo2Qk5XMFZ0c2NHdEhtQ3JzNzRqUGV6aHdOVDh5cGt5UytUMHpUNFRzeTZmClZYa0o4WVNIeWVuU3pNQjJPcDJidnNFM2dyWStzNzRXaEc5VUlBNkRCeGNUaWUxNU5Tekt3Znphb05XT0RjTEYKcDdCWThhYUhFMk1xRnhZRlgrSWJqcGtRUmZhZVFRc291REZkQ2tYRUZWZlBwYkQyZGs2RmxlYU1UUHV5eHRJVApnalZFdEdRSzJxR0NGR2lRSEZkNGhmVitlQ0E2M0pybzF6MHpvQk01QmJJSVEzK2VWRnd0M0FsWnA1VVZ3cjZkCnNlY3FraS95cm12M1kwZHFaOVZPbjNVQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ==
       signedIdentity:
         type: RemapIdentity
         matchPolicy: RemapIdentity
         remapIdentity:
           prefix: quay.local.momolab.io:443/mirror/openshift/release-images
           signedPrefix: quay.io/openshift-release-dev/ocp-release
    

    Apply the output files in the following sequence:

    # Step 1: Mirror image references
    oc apply -f idms-oc-mirror.yaml
    oc apply -f itms-oc-mirror.yaml
    
    # Step 2: Trust signatures
    oc apply -f signature-configmap.yaml
    oc apply -f ClusterImagePolicies.yaml
    
    # Step 3: Catalogd content (new way)
    oc apply -f cc-*.yaml
    
    # Step 4: Legacy CatalogSource (optional)
    oc apply -f cs-*.yaml

    Apply Generated ClusterImagePolicy YAML:

    $ oc create -f ClusterImagePolicies.yaml
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-ansible-automation-platform created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-ansible-automation-platform-25 created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-datagrid created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-lvms4 created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-odf4 created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-openshift-gitops-1 created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-openshift-service-mesh created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-openshift-service-mesh-dev-preview-beta created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-openshift-service-mesh-tech-preview created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-release created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-release-images created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-openshift4 created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-quay created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-rh-sso-7 created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-rhacm2 created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-rhbk created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-rhceph created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-rhel8 created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-rhel9 created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-rhem created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-service-interconnect created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-ubi8 created
    clusterimagepolicy.config.openshift.io/enforce-signatures-quay-mirror-ubi9 created

    Check the current policies as follows:

    $ oc get clusterimagepolicy
    NAME                                                                     AGE
    enforce-signatures-quay-mirror-ansible-automation-platform               104s
    enforce-signatures-quay-mirror-ansible-automation-platform-25            104s
    enforce-signatures-quay-mirror-datagrid                                  104s
    enforce-signatures-quay-mirror-lvms4                                     104s
    enforce-signatures-quay-mirror-odf4                                      104s
    enforce-signatures-quay-mirror-openshift-gitops-1                        104s
    enforce-signatures-quay-mirror-openshift-service-mesh                    104s
    enforce-signatures-quay-mirror-openshift-service-mesh-dev-preview-beta   103s
    enforce-signatures-quay-mirror-openshift-service-mesh-tech-preview       103s
    enforce-signatures-quay-mirror-openshift4                                103s
    enforce-signatures-quay-mirror-quay                                      103s
    enforce-signatures-quay-mirror-release                                   103s
    enforce-signatures-quay-mirror-release-images                            103s
    enforce-signatures-quay-mirror-rh-sso-7                                  103s
    enforce-signatures-quay-mirror-rhacm2                                    103s
    enforce-signatures-quay-mirror-rhbk                                      103s
    enforce-signatures-quay-mirror-rhceph                                    103s
    enforce-signatures-quay-mirror-rhel8                                     103s
    enforce-signatures-quay-mirror-rhel9                                     103s
    enforce-signatures-quay-mirror-rhem                                      103s
    enforce-signatures-quay-mirror-service-interconnect                      103s
    enforce-signatures-quay-mirror-ubi8                                      103s
    enforce-signatures-quay-mirror-ubi9                                      103s
    openshift                                                                5m7s
    

    Testing signature verification

    For this demonstration, we use two versions of the ubi9 image. The first is the signed image, mirrored with its signature: quay.local.momolab.io:443/mirror/ubi9/ubi:latest. The second is an unsigned version that was pushed manually to the registry: quay.local.momolab.io:443/mirror/ubi9/ubi:no-sig.

    Create a new project as follows:

    $ oc new-project verification

    Test with no signature, assuming you are already authenticated to your cluster:

    $ oc run test-ubi9-no-sig \
      --image=quay.local.momolab.io:443/mirror/ubi9/ubi:no-sig \
      --restart=Never \
      --overrides='{
        "apiVersion": "v1",
        "spec": {
          "containers": [{
            "name": "test-ubi9-no-sig",
            "image": "quay.local.momolab.io:443/mirror/ubi9/ubi:no-sig",
            "command": ["sleep", "infinity"],
            "securityContext": {
              "runAsNonRoot": true,
              "allowPrivilegeEscalation": false,
              "capabilities": {
                "drop": ["ALL"]
              },
              "seccompProfile": {
                "type": "RuntimeDefault"
              }
            }
          }]
        }
      }'

    Check the status of your pod:

    $ oc get pods
    NAME               READY   STATUS                      RESTARTS   AGE
    test-ubi9-no-sig   0/1     SignatureValidationFailed   0          11s

    Test with signature:

    $ oc run test-ubi9-with-sig \
      --image=quay.local.momolab.io:443/mirror/ubi9/ubi:latest \
      --restart=Never \
      --overrides='{
        "apiVersion": "v1",
        "spec": {
          "containers": [{
            "name": "test-ubi9-with-sig",
            "image": "quay.local.momolab.io:443/mirror/ubi9/ubi:latest",
            "command": ["sleep", "infinity"],
            "securityContext": {
              "runAsNonRoot": true,
              "allowPrivilegeEscalation": false,
              "capabilities": {
                "drop": ["ALL"]
              },
              "seccompProfile": {
                "type": "RuntimeDefault"
              }
            }
          }]
        }
      }'

    Check the status of your pod:

    $ oc get pods
    NAME                 READY   STATUS                      RESTARTS   AGE
    test-ubi9-no-sig     0/1     SignatureValidationFailed   0          40s
    test-ubi9-with-sig   1/1     Running                     0          4s

    You can confirm that verification is working by using Podman with the following steps.

    Log in to the node via debug mode:

    $ oc debug node/sno1.local.momolab.io
    Temporary namespace openshift-debug-82g7n is created for debugging node...
    Starting pod/sno1localmomolabio-debug-klhq9 ...
    To use host binaries, run `chroot /host`
    Pod IP: 192.168.1.231
    If you don't see a command prompt, try pressing enter.
    sh-5.1# chroot /host

    Test pulling a container with no signature. Log in to the registry first:

    sh-5.1# podman login quay.local.momolab.io:443
    Username: quayadmin
    Password: 
    Login Succeeded!

    Test pulling an unsigned container image:

    sh-5.1# podman --log-level debug pull quay.local.momolab.io:443/mirror/ubi9/ubi:no-sig 2>&1 | grep signatures  
    time="2025-08-04T00:46:27Z" level=debug msg="Error pulling candidate quay.local.momolab.io:443/mirror/ubi9/ubi:no-sig: Source image rejected: None of the signatures were accepted, reasons: cryptographic signature verification failed: crypto/rsa: verification error; cryptographic signature verification failed: crypto/rsa: verification error; Signature for identity \"registry.redhat.io/ubi9/ubi:9.6\" is not accepted; Signature for identity \"registry.redhat.io/ubi9/ubi:9.6-1749542372\" is not accepted; Signature for identity \"registry.redhat.io/ubi9/ubi:latest\" is not accepted; Signature for identity \"registry.access.redhat.com/ubi9/ubi:9.6\" is not accepted; Signature for identity \"registry.access.redhat.com/ubi9/ubi:9.6-1749542372\" is not accepted; Signature for identity \"registry.access.redhat.com/ubi9/ubi:latest\" is not accepted; Signature for identity \"registry.redhat.io/ubi9/ubi:9.6\" is not accepted; Signature for identity \"registry.redhat.io/ubi9/ubi:9.6-1749542372\" is not accepted; Signature for identity \"registry.redhat.io/ubi9/ubi:latest\" is not accepted; Signature for identity \"registry.access.redhat.com/ubi9/ubi:9.6\" is not accepted; Signature for identity \"registry.access.redhat.com/ubi9/ubi:9.6-1749542372\" is not accepted; Signature for identity \"registry.access.redhat.com/ubi9/ubi:latest\" is not accepted"
    Error: Source image rejected: None of the signatures were accepted, reasons: cryptographic signature verification failed: crypto/rsa: verification error; cryptographic signature verification failed: crypto/rsa: verification error; Signature for identity "registry.redhat.io/ubi9/ubi:9.6" is not accepted; Signature for identity "registry.redhat.io/ubi9/ubi:9.6-1749542372" is not accepted; Signature for identity "registry.redhat.io/ubi9/ubi:latest" is not accepted; Signature for identity "registry.access.redhat.com/ubi9/ubi:9.6" is not accepted; Signature for identity "registry.access.redhat.com/ubi9/ubi:9.6-1749542372" is not accepted; Signature for identity "registry.access.redhat.com/ubi9/ubi:latest" is not accepted; Signature for identity "registry.redhat.io/ubi9/ubi:9.6" is not accepted; Signature for identity "registry.redhat.io/ubi9/ubi:9.6-1749542372" is not accepted; Signature for identity "registry.redhat.io/ubi9/ubi:latest" is not accepted; Signature for identity "registry.access.redhat.com/ubi9/ubi:9.6" is not accepted; Signature for identity "registry.access.redhat.com/ubi9/ubi:9.6-1749542372" is not accepted; Signature for identity "registry.access.redhat.com/ubi9/ubi:latest" is not accepted

    Note the key phrase in the output: 'Signatures for identity...is not accepted'. Also note the key phrase in the output: 'Storing signatures'.

    Test pulling a container with a signature:

    sh-5.1# podman --log-level debug pull quay.local.momolab.io:443/mirror/ubi9/ubi:latest 2>&1 | grep signatures
    Getting image source signatures
    Checking if image destination supports signatures
    Storing signatures
    time="2025-08-04T00:46:56Z" level=debug msg="saved image metadata \"{\\\"signature-sizes\\\":[699,699,4156,4164,4160,4160,4180,4168],\\\"signatures-sizes\\\":{\\\"sha256:b2572b4ec08febca6587d5833d6e64054236cee20f03c481e6cf7ef90088e4e0\\\":[699,699,4156,4164,4160,4160,4180,4168]}}\""

    Notice the keywords above Storing signatures.

    Signature verification with oc-mirror

    As noted in the documentation, it is possible to configure oc-mirror to verify signatures while mirroring content. While selective verification is possible, this article demonstrates how to enable signature verification for all images using the --secure-policy=true flag.

    To enforce signature verification during the mirroring process, add the --secure-policy=true flag to the oc-mirror command.

    oc-mirror --v2 --image-timeout 20m0s --retry-times 5 --retry-delay 5s --remove-signatures=false --secure-policy=true -c  v2_imageset-config_all_RHOperators_4.19.yml --workspace file:///data/oc-mirror/workdir/  --log-level info docker://quay.local.momolab.io:443/mirror

    This method works as long as signatures are available for all images. If signatures are missing for some images, further customization will be required.

    Wrap up

    As demonstrated, the latest features in oc-mirror and OpenShift Container Platform 4.19 make it possible to enforce container signature verification in disconnected clusters.

    This proof of concept shows that by mirroring container images along with their signatures, organizations can enforce security policies and ensure image integrity, even in isolated environments.

    Related Posts

    • Disconnected OpenShift Virtualization made easy

    • How oc-mirror version 2 enables disconnected installations in OpenShift 4.16

    • How to work around Docker's new download rate limit on Red Hat OpenShift

    • How to get Red Hat OpenShift operators' information without oc-mirror plug-in

    Recent Posts

    • A deep dive into Apache Kafka's KRaft protocol

    • Staying ahead of artificial intelligence threats

    • Strengthen privacy and security with encrypted DNS in RHEL

    • How to enable Ansible Lightspeed intelligent assistant

    • Why some agentic AI developers are moving code from Python to Rust

    What’s up next?

    Because application images are prebuilt for use in containers, using server-defined environment variables in client-side scripts seems impossible. However, there is a way to inject variable values at runtime—this learning path reveals one method.

    Start the activity
    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Products

    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform

    Build

    • Developer Sandbox
    • Developer Tools
    • Interactive Tutorials
    • API Catalog

    Quicklinks

    • Learning Resources
    • E-books
    • Cheat Sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site Status Dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2025 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Report a website issue