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.
The post How to verify container signatures in disconnected OpenShift appeared first on Red Hat Developer.