πŸ“šBook Signing at KubeCon EU 2026Meet us at Booking.com HQ (Mon 18:30-21:00) & vCluster booth #521 (Tue 24 Mar, 12:30-1:30pm) β€” free book giveaway!RSVP Booking.com Event
Configuration intermediate ⏱ 15 minutes K8s 1.28+

OpenShift IDMS ITMS Mirror Rules Guide

Configure IDMS and ITMS mirror rules in OpenShift for disconnected registries. NeverContactSource vs AllowContactingSource and ICSP migration.

By Luca Berton β€’ β€’ πŸ“– 5 min read

πŸ’‘ Quick Answer: ImageDigestMirrorSet (IDMS) and ImageTagMirrorSet (ITMS) are the OpenShift 4.13+ replacements for the deprecated ImageContentSourcePolicy (ICSP). IDMS rewrites image pulls by digest (@sha256:...) to your mirror registry; ITMS rewrites tag-based pulls (:latest). Set mirrorSourcePolicy: NeverContactSource for strict air-gap or AllowContactingSource for hybrid environments where the mirror is preferred but upstream is a fallback.

The Problem

Disconnected OpenShift clusters need to redirect all image pulls from Red Hat/Quay registries to a local mirror. The old ICSP had limitations:

  • Only supported digest-based mirrors
  • No tag-based mirroring
  • No fallback policy control
  • Maximum 250 mirrors per ICSP (performance issues)
  • Deprecated in OpenShift 4.13+

The Solution

IDMS β€” ImageDigestMirrorSet

For images pulled by digest (most OCP internal components):

apiVersion: config.openshift.io/v1
kind: ImageDigestMirrorSet
metadata:
  name: ocp-release-mirror
spec:
  imageDigestMirrors:
  # OCP release images
  - mirrors:
    - registry.example.com:5000/openshift/release-images
    source: quay.io/openshift-release-dev/ocp-release
    mirrorSourcePolicy: NeverContactSource

  # OCP component images
  - mirrors:
    - registry.example.com:5000/openshift/release
    source: quay.io/openshift-release-dev/ocp-v4.0-art-dev
    mirrorSourcePolicy: NeverContactSource

  # Red Hat operator images
  - mirrors:
    - registry.example.com:5000/rhel9
    source: registry.redhat.io/rhel9
    mirrorSourcePolicy: NeverContactSource

ITMS β€” ImageTagMirrorSet

For images pulled by tag (operators, user workloads):

apiVersion: config.openshift.io/v1
kind: ImageTagMirrorSet
metadata:
  name: operator-mirror
spec:
  imageTagMirrors:
  - mirrors:
    - registry.example.com:5000/redhat/redhat-operator-index
    source: registry.redhat.io/redhat/redhat-operator-index
    mirrorSourcePolicy: NeverContactSource

  - mirrors:
    - registry.example.com:5000/openshift-update-service/graph-data
    source: registry.redhat.io/openshift-update-service/graph-data
    mirrorSourcePolicy: NeverContactSource

Mirror Source Policies

PolicyBehaviorUse Case
NeverContactSourceOnly use mirror. Fail if mirror unavailable.Strict air-gap, no internet
AllowContactingSourceTry mirror first, fall back to source.Hybrid, mirror as cache
graph TD
    PULL[Image Pull Request] --> IDMS{IDMS/ITMS<br/>Rule Matches?}
    IDMS --> |Yes| MIRROR[Try Mirror Registry]
    IDMS --> |No| SOURCE[Pull from Source]
    MIRROR --> OK{Success?}
    OK --> |Yes| DONE[Image Pulled βœ…]
    OK --> |No| POLICY{mirrorSourcePolicy?}
    POLICY --> |NeverContactSource| FAIL[Pull Failed ❌]
    POLICY --> |AllowContactingSource| SOURCE
    SOURCE --> DONE
    
    style FAIL fill:#F44336,color:white
    style DONE fill:#4CAF50,color:white

Migrate from ICSP to IDMS

# Check existing ICSPs
oc get imagecontentsourcepolicy

# Auto-convert ICSP to IDMS
oc adm migrate icsp /path/to/icsp.yaml --dest-dir /tmp/idms/

# Or manually convert:
# ICSP:                    β†’ IDMS:
# kind: ImageContentSourcePolicy  β†’ kind: ImageDigestMirrorSet
# spec:                           β†’ spec:
#   repositoryDigestMirrors:      β†’   imageDigestMirrors:
#   - mirrors:                    β†’   - mirrors:
#     - mirror.example.com/repo   β†’     - mirror.example.com/repo
#     source: quay.io/repo        β†’     source: quay.io/repo
#                                 β†’     mirrorSourcePolicy: NeverContactSource

# Apply IDMS, then remove ICSP
oc apply -f /tmp/idms/
oc get idms  # Verify
oc delete icsp --all  # Remove deprecated ICSPs

# Nodes will rolling-reboot to update /etc/containers/registries.conf
oc get mcp -w

What Happens on the Node

IDMS/ITMS translate to CRI-O registry configuration:

# After IDMS apply, each node gets:
# /etc/containers/registries.conf.d/XXX-idms.conf

[[registry]]
  prefix = ""
  location = "quay.io/openshift-release-dev/ocp-release"
  blocked = true  # NeverContactSource

  [[registry.mirror]]
    location = "registry.example.com:5000/openshift/release-images"

[[registry]]
  prefix = ""
  location = "registry.redhat.io/redhat/redhat-operator-index"
  blocked = true

  [[registry.mirror]]
    location = "registry.example.com:5000/redhat/redhat-operator-index"

Verify Mirror Rules

# List all mirror sets
oc get idms,itms

# Check node registry configuration
oc debug node/worker-0 -- chroot /host \
  cat /etc/containers/registries.conf.d/*.conf

# Test image pull through mirror
oc debug node/worker-0 -- chroot /host \
  crictl pull registry.example.com:5000/openshift/release-images:4.20.12-x86_64

# Check which registry a pod is actually pulling from
oc get pod <pod> -o jsonpath='{.status.containerStatuses[*].imageID}'

Common Issues

Nodes stuck rebooting after IDMS apply

IDMS changes trigger MachineConfig updates β†’ rolling reboot. If stuck, check MCP: oc describe mcp worker. Common cause: invalid mirror URL in IDMS.

β€œimage not found” despite IDMS configured

IDMS only works for digest-based pulls. If the image is pulled by tag, you need ITMS. Check the failing pull with oc describe pod β€” look for @sha256: (IDMS) vs :tag (ITMS).

Multiple IDMS with overlapping sources

Allowed β€” mirrors are tried in order. First successful pull wins. Use separate IDMS per source registry for clarity.

Performance degradation with many mirror rules

Keep IDMS count reasonable. CRI-O checks rules sequentially. Consolidate mirrors for the same source into one IDMS entry.

Best Practices

  • IDMS for platform, ITMS for operators β€” OCP internals use digests, operator catalogs use tags
  • NeverContactSource for air-gap β€” prevents accidental internet access
  • Migrate from ICSP β€” ICSP is deprecated; use oc adm migrate icsp
  • Let oc-mirror generate them β€” don’t hand-write IDMS/ITMS; use oc-mirror’s cluster-resources/
  • One IDMS per logical source β€” easier to manage than one giant IDMS

Key Takeaways

  • IDMS rewrites digest-based pulls, ITMS rewrites tag-based pulls
  • NeverContactSource = strict air-gap; AllowContactingSource = mirror-preferred with fallback
  • IDMS/ITMS replace the deprecated ICSP (OpenShift 4.13+)
  • Mirror rules translate to /etc/containers/registries.conf.d/ on each node
  • Changes trigger MCP rolling reboot β€” plan for maintenance window
  • oc-mirror generates correct IDMS/ITMS automatically in cluster-resources/
#openshift #idms #itms #disconnected #registry #mirror
Luca Berton
Written by Luca Berton

Principal Solutions Architect specializing in Kubernetes, AI/GPU infrastructure, and cloud-native platforms. Author of Kubernetes Recipes and creator of CopyPasteLearn courses.

Kubernetes Recipes book cover

Want More Kubernetes Recipes?

This recipe is from Kubernetes Recipes, our 750-page practical guide with hundreds of production-ready patterns.

Luca Berton Ansible Pilot Ansible by Example Open Empower K8s Recipes Terraform Pilot CopyPasteLearn ProteinLens